Note All notes →
5 min read

A feed was dead for two weeks. All my logs said was "2 feeds failed".

I logged which feeds failed but not why. The morning after I started logging the reason, the cause showed up, and one of them had been arriving with a success-family status code.

This is not a news summary. It is a record of something that happened while building this site.

An unattended pipeline reads 12 news feeds every morning at 08:00. One of them had returned nothing since August 9, and I did not notice until August 21. Not for lack of monitoring: the record said "2 feeds failed" every single day.

The number was correct. There was just nothing I could do with it.

At first I thought the feed was malformed

When a feed could not be read, this is what got logged.

[WARN] Hacker News (AI) fetch failed: parse error: <unknown>:7:2: mismatched tag

"Parse error" plus "mismatched tag on line 7" reads like broken feed XML, so that is where you go looking.

That is not what happened. The server was returning 502 with an nginx error page, and we were parsing that HTML as XML until it tripped on line 7. The feed was fine. The server was down and there was nothing on our side to fix.

I logged the names. It still was not enough

On August 20 I made the pipeline record the names of failed feeds in that day's file. Before that only a count survived, so a few days later there was no way to tell which feeds they had been.

The next morning the names appeared. MarkTechPost, Hacker News. And that is where it stopped. Knowing the name does not tell you what to do next. A site blocking us and a server being sick are entirely different problems, and a name does not separate them.

This repo has a rule: when a domain you should be able to reach fails, check the network allowlist first. It had been the cause twice before. I checked, and both hosts were on the list.

My laptopUnattended environment
MarkTechPostHTTP 200 · valid RSScould not read
Hacker News (AI)HTTP 200 · valid XMLcould not read

The same URL opens from one place and not the other. To get any further I needed to know what the failing side actually received, and that value was printed to the console once and gone when the run ended.

So I made it keep the reason

The change is small. Instead of throwing the exception message away, write it into that day's record. If there is a status code, lead with it. If a response arrived but the content is not XML, say that. If neither, it might genuinely be a format problem, so show the original exception.

I nearly got this wrong. My first version only reported status codes of 400 and above. Left that way, it would have missed half of what showed up the next morning.

The next morning, two feeds, two different reasons

MarkTechPost      not a feed (content-type: text/html, HTTP 202)
Hacker News (AI)  HTTP 502 - error response instead of a feed, content-type: text/html

MarkTechPost sits behind Cloudflare, which serves a human-verification page to requests from datacenters. That page arrives as 202. We asked for RSS and got a page meant for a person to look at, and by response code alone nothing was wrong.

Hacker News was not our problem. That server is struggling and will come back. It timed out from my home connection too.

What the two weeks cost

The briefing never stopped. One dead feed does not halt the others, by design. What happened instead was a quiet narrowing. Reading 11 sources instead of 12 means each remaining outlet takes a bigger share. On August 21, four outlets filled all ten slots.

The more expensive cost was elsewhere. When "2 feeds failed" appears every day and there is nothing you can act on, that line becomes one you read and do nothing about. A few days of that and a genuinely new failure would not register either. That is exactly why it took two weeks.

After the fix

On August 23 I dropped MarkTechPost. There is no way around a Cloudflare challenge from a datacenter address. Instead I opened 31 candidate feeds and screened them on four things.

  • Is it behind Cloudflare? That is what just killed us, so I am not buying the same risk again
  • Are the actual headlines about AI, rather than the section being named that? Several "AI" feeds were serving how-to articles about televisions
  • Can the article body be fetched? Titles alone just occupy a slot
  • Is the publishing volume enough to matter?
CandidateCloudflarePer weekArticle body
The Decoderno10readable
SiliconANGLE AIno30readable
Hugging Face Blogno5readable
The Register AI/MLno4readable
Simon Willison · Latent Space · AI Businessyes--

Of the ones that cleared all four I picked The Decoder. Ten posts a week, all of them on AI, with a lot of research write-ups, which is close to the role the dropped feed had been filling.

What I am taking from it

The record grew three times: a count, then a name, then a reason. With only the first two, writing it down every morning changed nothing. "What failed" is a line you read and move past. "So what do I do" is the one that gets you out of your chair.

This one came back 202. The next one might come back 200. So the check reads the body, not just the code.

How this site picks what it picks is written up in About, and the daily intake and publication figures are on the Data page.