At 03:14 UTC on a Tuesday, a keeper bot on an optimistic rollup executed forty-one liquidations against a lending market that carried no bad debt. The bot was not malfunctioning. The oracle returned an integer. The contract accepted the integer. The integer was 4,112 โ the value an aggregator emits when every upstream feed times out and the median function is handed a quorum of nothings. Nothing reverted. The event log wrote LiquidationCall. The monitoring dashboard, which sampled liveness and not correctness, showed green across fourteen panels. The post-mortem showed an empty field where a price should have been, and no line of code anywhere in the stack that treated an empty field as an error.
I have run that audit eleven times in four years. In nine of them the failure was not a revert. It was a call that succeeded and returned nothing, and a downstream system that had been carefully engineered to read nothing as a number.
This is the failure mode the industry does not price. Exploits get post-mortems, reimbursements, and a token relaunch with a new ticker. Silent failures get a Slack thread and a quiet patch. But silent failure is the more expensive of the two, because it does not stop the system โ it lets the system keep making decisions on a fiction, at machine speed, for as long as nobody thinks to look.
Last quarter I reviewed a research pipeline. Not a trading system โ a research pipeline, the kind of thing that ingests a document and emits a structured analytical report. It produced fourteen fields: title, source, classification, summary, author stance, stated purpose, information points, referenced protocols, time sensitivity, source quality. All fourteen fields came back populated. All fourteen fields were populated with the string "not provided," or "unclassified," or "undetermined." The pipeline exited zero. It logged no warnings. It wrote a clean file. Structurally, the report was perfect. It contained zero facts, and it was indistinguishable, at the level of the schema, from a report that contained fourteen verified ones.
That is not an AI problem, and it is not a parsing problem. It is a schema problem, and the schema problem is the same one that liquidated forty-one healthy positions at 03:14 UTC. When absence is a legal value, absence becomes unobservable. And anything unobservable cannot be audited, cannot be alerted on, and cannot be priced.
The crypto stack is a stack of optimistic pipelines. An RPC provider, a subgraph indexer, an oracle aggregator, a bridge relayer, an attestation service, a MEV relay โ every one of them is a component that receives a query, attempts a resolution, and returns something. The entire industry has spent a decade instrumenting the "returns something" branch. Almost nobody has instrumented the other branch, because the other branch does not throw.

We measure what is cheap to measure. Uptime is cheap: ping the endpoint, get a 200, paint the panel green. Latency is cheap: timestamp the request, timestamp the response, subtract. Block height is cheap: compare the head to the public head and alert on drift. None of these measure whether the payload was true. A subgraph that is four thousand blocks behind will answer every query you send it, in eleven milliseconds, with HTTP 200, and an empty array.
The reason correctness is under-instrumented is that correctness requires a ground truth you do not have. You cannot write an assertion for "this price is right" without a second independent price, and the moment you have a second price you have a divergence problem, which is a harder problem than a liveness problem, and which most teams solve by taking the median and calling it consensus. The median of five feeds that are all reading the same three venues is not consensus. It is one feed with extra steps and a confidence interval that is a lie.
The historical record is instructive precisely because the famous failures are not this kind. In November 2020, roughly $89 million of DAI was liquidated on Compound because the price feed faithfully reported a price that existed on exactly one thin venue and nowhere else. That feed was not stale. It was not empty. It was accurate to a source that was not representative โ a different disease with the same symptom, and one that at least left a number behind for the post-mortem to argue about. The Terra collapse in May 2022 was not a data failure at all; it was a model failure wearing data as a costume, a peg defended by an incentive that only worked while the incentive was being paid. I shorted it with a 3x position and a hard stop because the stress test said the mechanism was a loop, not because the feed was broken. Those failures are legible. They generate a chart with a shape.
Silent failure generates no chart. It generates a flat line, and a flat line reads as calm.
Consider what actually breaks. There are three classes, and they share one property: no in-band error signal.
The first is the stale oracle round. latestRoundData() on a Chainlink aggregator returns five values โ roundId, answer, startedAt, updatedAt, answeredInRound. The overwhelming majority of consuming contracts in production check exactly one thing: that answer is greater than zero. That check is a liveness check wearing the costume of a correctness check. A round that is eleven hours old still returns a positive integer. A round where answeredInRound < roundId โ meaning the answer was carried forward from a previous round rather than freshly computed โ still returns a positive integer. Chainlink's own documentation says to validate updatedAt against a heartbeat and to assert answeredInRound >= roundId. Almost nobody does. The code passes review because require(price > 0) looks like validation, and it is validation, of the wrong proposition.
The second is the empty collection. You query an indexer for a wallet's open positions and it returns []. You query eth_getLogs over a block range that has been pruned and the provider returns [] rather than an error, because returning an error would cost it an SLA credit. You ask a subgraph for a market's liquidation events and it returns [] because its indexing cursor stalled during a reorg and it never recovered. In all three cases the response is well-formed, the status code is 200, and the type is array. There is no in-band bit that distinguishes "zero" from "unknown." Downstream, that empty array flows into an accounting table, a risk score, a dashboard widget that renders 0, and a human who reads 0 as good news. The most dangerous API response in this industry is a successful one with nothing in it.
The third is the schema default, which is the class that produced the fourteen-field report. Someone writes an enum for a status field: provided | not_provided | unclassified. The intent is that not_provided is a sentinel that triggers a retry. The behavior is that not_provided is a member of the enum, therefore a valid value, therefore a value that passes the type checker, therefore a value that lands in the output artifact and gets shipped. The sentinel colonizes the schema. Once absence is typed, absence is invisible to every validator that checks for presence rather than for population. Exit code zero. Clean file. Fourteen fields of nothing.
| Failure class | In-band error signal | Typical detection latency | Who actually catches it | Blast radius | |---|---|---|---|---| | Stale oracle round | None | 3โ40 blocks | Liquidators, post-hoc | Position-level | | Empty log or query range | None (HTTP 200) | Hours to days | Reconciliation, if it exists | Accounting drift | | Schema default accepted | None (exit 0) | Weeks | Manual audit | Report integrity | | Reorg beyond confirmation depth | Partial | 1โ2 epochs | Bridge invariants | Systemic | | Sequencer silence | None | Minutes | Users, via failed UX | Market-wide |
I score every pipeline I touch on two numbers, and I have been doing it since 2017, when I built a slippage-arbitrage script against Bancor's conversion rate and learned that the hard part was never the strategy โ it was proving the inputs were live. The two numbers are coverage and assertion density. Coverage is the fraction of output fields that carry a non-null value with an attached source_uri and fetched_at. Assertion density is the number of explicit correctness checks per hundred fields of output. A pipeline I would put capital behind runs a coverage above 0.98 and an assertion density between eight and fifteen. The fourteen-field report ran a coverage of 0.00 and an assertion density of 0.6. It passed every gate that existed, because the only gate that existed was a null-check on the file handle.
The fix is not exotic. It is four gates, applied in order, and each one fails closed.

Gate one is population. Every field must carry provenance โ a source identifier and a fetch timestamp โ and any field resolving to a sentinel must raise rather than serialize. Not warn. Raise. A report with an empty required field is a failed report, not a sparse one.
Gate two is freshness. Assert now - fetched_at < heartbeat / 2 at consumption time, not at fetch time, because the gap between the two is where staleness lives. This is a two-line check that would have prevented the Compound-adjacent class of error and costs nothing.
Gate three is divergence. Two independent sources, an explicit tolerance, and an alert on breach. Independence is the hard part: two feeds that both read the same three venues are one feed. If you cannot establish independence, you do not have a cross-check, you have a decoration.
Gate four is the one almost nobody runs, and it is the one I now insist on before I trust any pipeline. Feed it nothing and assert that it screams. Inject a null fixture โ a document with no content, an oracle response with an empty answer, a block range that returns zero logs โ and require the pipeline to exit non-zero and emit an alert. If it exits zero, the pipeline is broken regardless of what it did on the last real input, because a pipeline that cannot detect absence cannot detect anything; it can only detect the failures it was written to imagine. I have started calling this the null canary, and in eleven audits it has failed nine times. The two that passed were both built by people who had already been burned.
There is a second-order amplification that makes all of this worse, and it lives in the lending markets. The rate curves on Aave and Compound are kinked models: a shallow slope below the optimal utilization, a steep one above it. Past the kink, the marginal rate response is roughly an order of magnitude larger per unit of utilization. That means a two percent error in a utilization figure computed from a feed that silently returned a stale reserve balance does not produce a two percent error in the borrow rate. It produces something closer to twenty. The curve is a lever bolted onto the data, and the lever has no idea whether the data was real. This is the part of the risk surface that governance forums discuss least, because the parameters are legible and the inputs are not, and legible things get debated while invisible things get assumed.
And here is the contrarian part, the part that will annoy the infrastructure crowd: the industry's standard response to this problem is to add more data, and adding more data makes it worse. Every additional feed, indexer, dashboard, and attestation layer is another surface where absence can be typed as a value, another integration that returns 200 with nothing inside, another panel that turns green when the payload is empty. Redundancy without divergence checking is not redundancy. It is correlation with extra steps and a higher bill.
The Data Availability layer is the clearest case. The pitch is that rollups need guaranteed availability, so we are building dedicated DA committees, DA marketplaces, and DA sampling schemes with cryptographic guarantees. Fine. But go count the bytes. The overwhelming majority of rollups in production today do not generate enough data per block to stress a shared calldata field, let alone require a purpose-built sampling layer. They are buying capacity against a future they have not reached, and paying for it with a trust assumption they have not audited. Meanwhile their actual correctness problem โ the one that will produce the bad block โ sits in the indexer that stalled two days ago and the oracle wrapper that checks answer > 0. Liquidity is a vanishing act, not a guarantee, and so is data availability: the guarantee is only as good as the consumer's willingness to verify it arrived.
Then there is the accountability layer, which is where I have the least patience. Audit firms are paid for findings, and a finding is a positive statement about a thing that exists. Absence is not a positive statement. "We found nothing" and "we looked at nothing" produce the same page, the same signature, the same invoice. The standard verification process is a review of controls, and controls are process artifacts; a pipeline with perfect controls and a 0.00 coverage ratio passes a controls review with distinction. When Terra's mechanism failed, the audits that had blessed it were not wrong about the code. They were answering a different question than the one that mattered, and the question they were answering had a deliverable attached. That is not fraud. It is worse โ it is a structurally unfalsifiable product, sold at a fixed fee, to buyers who need the signature more than they need the truth. Audit trails are the only legacy that matters, and a trail of clean signatures on empty reports is not a trail. It is a receipt.

The same disease shows up in the least likely place: NFT floor feeds. A collection's floor price is the minimum ask across live listings, which means that when listings dry up, the computed floor does not fall โ it becomes undefined, and undefined gets handled by whatever the aggregator's default happens to be. Floor prices are just opinions with timestamps, and a floor feed with zero listings is not a price at all, it is a memory. I swept fifteen CryptoPunks in 2021 at an average of 4.5 ETH because my screening model required a minimum listing depth before it would accept a floor as an input, and I sold twelve at an average of 85 ETH. The edge was not the rarity score. The edge was refusing to price an asset off a book that had gone quiet. Ledger books don't lie. They go quiet, and quiet is the thing you have to build for.
So here is the forward-looking judgment, and it is not a summary. The next nine-figure loss in this industry will not be a bridge exploit and it will not be a key compromise. It will be a report that validated cleanly. It will be a keeper bot that did exactly what its code said, on a number that came from nowhere, and a dashboard that stayed green through all of it because green was wired to liveness and nobody wired anything to truth. Volatility is the tax on indecision, but silent failure is the tax on confidence, and it compounds quietly in every system that treats an empty field as a valid answer.
Ask your own stack the question tonight: what does it do when the oracle reverts? Not when it lies โ when it returns nothing. If the answer is "it keeps running," then you do not have an oracle. You have a suggestion, wrapped in a require statement, wired to a lever. And the lever does not know.