How to notice your data pipeline died before someone tells you

The failure that raises no error: the row arrives fresh and the column comes back empty. Why the distortion always improves your metrics, a case we measured this week, and the three checks that catch it.

An integration that breaks with an error is a good day. Someone sees the error, someone fixes it, and the worst consequence is a while without data.

The problem is the other way of breaking: the one that produces no error at all. The job runs, the row is written, the run finishes green, and one field inside it comes back empty. For days, the dashboard shows numbers that are no longer true and nobody has any reason to doubt them.

The failure that produces nothing

Normal monitoring asks was there an error? That question is necessary and insufficient, because the most expensive failure mode answers no.

The missing question is different: when did this data last arrive? They are different questions and they need different mechanisms. The first is answered by reading logs; the second can only be answered by looking at the data itself.

A fresh row with a stale column

Here is the technical detail that decides whether your monitoring works. If the check asks “did today’s row arrive?”, the answer can be yes while half the table is empty inside.

That is what happens when a job consolidates several sources into one daily record. If one of those sources stops responding, the job does not fail: it writes the row with what it got and leaves the rest blank. The row is from today. The column is from two weeks ago.

The practical consequence: freshness is measured per column, not per row. And for that you need to distinguish two things many systems store identically:

  • Zero means “we measured and there was nothing”. It is data.
  • No data means “we did not measure”. It is the absence of data.

If both end up as 0 in the same column, you have already destroyed the information you needed to detect the problem.

The distortion goes in the flattering direction

This is what makes it more than a technical annoyance. When a cost source disappears, efficiency metrics do not get worse: they improve.

  • Total spend is understated.
  • MER, which divides revenue by spend, goes up.
  • CAC and cost per lead, which divide spend by results, go down.

So the system shows you a spectacular month exactly when it stopped seeing part of what you spent. Nobody questions a good number, which is why this error survives longer than any other. We wrote separately about what each of those metrics means in CAC, CPA, ROAS and MER.

A case we measured this week

What follows comes from querying our own system on 13 September 2026. We do not say which client or which platform — those accounts belong to each client — but the figures are real and were measured that day.

  1. An advertising spend source delivered its last data on 5 September.
  2. Daily rows kept being written without interruption through 12 September. Seven days of perfectly fresh rows with that column empty.
  3. It stopped on the same day in both accounts using that source. Two independent accounts stopping together is not a business decision: it is a broken pipeline.
  4. The status object written by the ingestion itself has no key for that source. It reported ok on everything it did know about. A monitor cannot warn about what is not on its list.
  5. That source accounted for 27.8% of advertising spend over the 31 days before the cut.

Translated into the metrics, calculated rather than estimated:

  • Spend understated by 27.8%.
  • MER inflated by 38.5%.
  • CAC and cost per lead 27.8% cheaper than reality.

A dashboard showing efficiency 38% better than the truth, for a week, without a single error in any log.

The three checks that catch it

CheckWhat it asksWhat it catches
Per-column freshnessWhen did THIS field last carry a valueThe source that died while the rest kept running
Volume against its own historyDid today bring more or less than usualThe feed delivering half, which is worse than none
Coherence between fieldsSpend with no impressions, sales with no leadsData that arrived, but arrived wrong

The first is the one that saves you. For each field feeding a metric, store the last date it carried a value and compare it against that source’s expected cadence. Our threshold for daily sources is three days; for a weekly source the same threshold would be pure noise. A single global number for everything produces either noise or blindness.

The second catches what the first lets through: the feed that did not die but brings half. That is worse than total absence, because the data looks right. Comparing today’s volume against that source’s usual band detects it.

The third finds what arrived wrong rather than what did not arrive: spend with no impressions, sales with no leads, a total that does not equal its parts. These are coherence rules between fields, and they get written once.

And the part we got wrong

Worth telling, because it is the real lesson of the case. The per-column freshness check existed and worked: queried, it reports the source as stale from the first day past the threshold.

The problem is that it was a pull endpoint. You had to go and ask it. Nothing pushed the finding toward a person: no email, no message, no line in the weekly summary. A check that works perfectly and that nobody runs is equivalent to not having one.

Which is why the last piece is not technical: who receives the alert and what they do with it. It is the same principle we apply to prioritising any automation — before building, define what failure looks like — and here we had skipped it in our own house.

FAQ

  • Why do error alerts not catch this? Because nothing errored. The pipeline ran, the row was written, the job finished green. What failed is that one field inside it arrived empty — and an empty field is a perfectly valid row.
  • Is a zero the same as no data? Never, and treating them the same is the root of the problem. Zero means “we measured and it was nothing”. No data means “we did not measure”. A system that stores both as 0 has thrown away the distinction it most needed.
  • What is a reasonable threshold? It depends on the cadence of each source, not on a single global number. A daily feed is late after two or three days. A weekly report is not late until well past a week. One threshold for everything produces either noise or blindness.
  • Is it worth building this for a small operation? The check is cheap: the last date each field carried a value. What costs is deciding who receives it and acting on it. If nobody will act, do not build the alert — build the habit of looking first.