The Bug That Ships as a Feature: What I Learned About Spend Caps the Hard Way
Admin User
Author
I shipped a broken spend cap last month. Not catastrophically broken—nothing caught fire—but broken in a way that made me realize I didn't actually understand what my own rate-limiting code was doing when the database went down.
It was 2 AM, our API was getting hammered, and the pricing oracle timed out. My cap didn't refuse requests. It didn't block them either. It just... kept going. And I only realized because a customer's bill was wrong. The decision I'd made about how to handle a missing price wasn't actually in my code—it was hiding in what I didn't write, in the exception handling I skipped because I assumed something else would catch it.
Reading this article about spend caps and oracle failures felt like someone had installed a camera in my apartment. I'm still thinking through the implications.
The Problem Is Worse Than the Framing
The traditional way we talk about this is "fail-open vs fail-closed." Fail open means you let requests through when you can't price them. Fail closed means you block everything. This framing made me feel clever—I could pick a side, add a config option, and move on.
But the article fundamentally breaks this apart. The real axis isn't open or closed. It's whether your ledger keeps counting.
When your pricing oracle goes down, you have a few choices. You can refuse requests (truly fail-closed). You can admit them without charging anything (ledger frozen). You can charge a pessimistic estimate. You can fall back to a local model. On paper, these look different. But some of them produce identical behavior—they both charge zero, they both stop the ledger from moving, they both create unaccounted-for actions in your system.
The article proves this with a cryptographic hash. Two different policies, different names, different philosophy, identical byte-for-byte decision streams. One gets called a bug. The other gets called the recommended fix. The difference is branding, not behavior.
This broke something in how I think about safety. I've been treating "use a local fallback model" as obviously more sophisticated than "fail-open." And it is more sophisticated in terms of user experience. But if both charge zero when the oracle is down, both have the same ledger problem. Neither solves the core issue.
The Real Cost: Moving vs Frozen Ledgers
Here's where it gets practical. If your ledger stops counting (zero charges), then when the oracle comes back online, you have no way to know what happened during the outage. Those 34 unpriced actions in the test scenario? They're ghosts. You can't audit them. You can't charge for them. You can't even know if someone exploited the gap.
But if you charge something—even a wildly inaccurate estimate—your ledger keeps moving. You have a floor. It might be wrong (a $0.05 action priced at $0.01), but at least there's something to audit and correct later.
The pessimistic strategy in the test data charges the per-action cap. It's almost certainly overcharging. But look at the results: ledger-moved=True. The accounting function knows something happened.
I'm sitting with this because it suggests the question isn't "what's the safe default?" The question is "what can I actually audit later?" A moving ledger with a bias is more honest than a frozen ledger that pretends nothing happened.
What I'm Actually Doing About This
I've already changed how I think about my spend cap. I'm adding explicit handling for oracle failures instead of hoping exceptions catch it. Here's the shape I'm moving toward:
def charge_or_estimate(action, budget, oracle):
try:
price = oracle.get_price(action)
return charge(action, price, budget)
except OracleDown:
# Don't freeze the ledger
estimated_price = get_last_known_price(action)
if estimated_price is None:
# Fallback to action cap if we have no history
estimated_price = self.per_action_cap
# Log it explicitly - this WILL be in the ledger as unverified
log_unverified_charge(action, estimated_price, reason="oracle_down")
return charge(action, estimated_price, budget)
The key difference: I'm making the failure case explicit and measurable, not hidden in exception handling. The ledger moves. The accounting team knows something happened during the outage.
Questions I'm Still Asking
Does this mean I should deliberately overestimate costs when the oracle is down? How much overestimation is acceptable? What's the business cost of blocking 90% of requests versus charging them at 2x estimated price?
And honestly—how many production systems have this bug right now, hiding in uncaught exceptions or in the invisible branches of error handling?
I'd like to know: have you shipped a spend cap or rate limiter? Did you explicitly handle the oracle failure case, or did you discover it the way I did?
Source: This post was inspired by "A Spend Cap That Stops Counting Is Already Fail-Open" by Dev.to. Read the original article