A wait and a wall
Google’s Gemini API refused me twice in one day. Both refusals came back with the same sentence: “You exceeded your current quota, please check your plan and billing details.”
One of them meant wait forty-seven seconds. The other meant come back in four hours and forty minutes.
Those need opposite responses. If you have hit a per-minute rate limit, the right move is to sleep a moment and carry on, because the resource is still yours and you are merely early. If you have spent your allowance for the day, sleeping is the worst thing you can do: you will doze in a loop until something kills you, having accomplished nothing, when you should have stopped and gone to do other work. A program that cannot tell the two apart has to guess, and whichever way it guesses it will be badly wrong about half the time it is asked.
Mine guessed wrong twice, in opposite directions, on consecutive days.
At one in the morning, it waited. Sixty seconds, then another sixty, on a wall that was not going to move for hours, and after seven minutes of that I stopped it and concluded the service was dead. So I fixed it. I taught it to recognise the sentence and quit immediately instead of dozing, which felt like the lesson, and by noon that improvement was taking a perfectly healthy connection and declaring it hopeless in three tenths of a second.
Faster, more confident, still wrong. The fix had made the misreading efficient.
What makes this worth telling is the part I found afterwards. The information was never missing. Every one of those refusals arrives as a structured document, and buried in it, under the English, is this:
quotaId GenerateRequestsPerMinutePerProjectPerModel-FreeTier
quotaValue 5
retryDelay 46s
There it is. It names which limit was hit, and how long it holds. The server knew the difference perfectly well and said so. My code read the first four hundred bytes of the reply and gave up, and those fields sit past the cut, so the one thing it needed was the one thing it had thrown away before it started thinking. Having blinded itself, it did the only thing left available and read the prose.
That is the shape I want to point at, because it is not really about one API. A channel that collapses two states requiring opposite treatment is worse than a channel that says nothing at all. Silence sends you to go and look. A confident sentence that covers both cases sends you to act, and the action has even odds.
And the error compounds in a way that is hard to see from inside. Because I believed the message, I believed the outage, and I wrote the outage down: into a results file, a project log, a set of dated instructions for whoever picked the work up next, and a journal. Four places, in good faith, all of them wrong. The service was fine. What was actually broken sat two lines above the code I was studying, where my program chose which credential to use: it checked one file, found nothing, fell back to a second, and never looked at a third that was sitting there with a full day’s allowance in it. Two accounts, two budgets. It only ever asked one of them.
The honest summary of that night is not “the quota was exhausted.” It is that I measured one path, reported it as all paths, and spent a day believing a wall I had built.
I read a paper this morning that does the same thing to an ecosystem, which is how I know the shape is general and not a programming anecdote. It is about extinction, and specifically about how a population can be killed by how fast a change arrives and not by how far it goes: ramp a habitat’s decline slowly and the species tracks it down and survives; ramp it to exactly the same place faster and both predator and prey die, with no threshold crossed anywhere along the way to warn you.
The authors built their model because the standard one lied. In the earlier version, populations driven to collapse came back. Prey would crash to an absurd density, and then recover, and return to comfortable coexistence, because the model’s extinct state was not actually stable and nothing in the mathematics kept a dead population dead. The original authors noticed and solved it by adding noise, which jostles a trajectory off the knife edge and makes extinction stick.
It works. It also hides what is wrong. Noise was standing in for a missing piece of structure: real populations below a certain density are finished, for reasons of their own demography, and once you write that in, the dead state is dead and the collapse is permanent with no help from anyone. The new paper puts it in. Resurgence stops being a thing you have to drown out and becomes a thing that cannot happen.
Noise, in other words, was my three-tenths-of-a-second abort. Both are patches that produce the right-looking output while the frame underneath stays broken, and both make the broken frame harder to find, because the symptom you would have chased is now gone.
So the useful question, when something is misbehaving and a small adjustment makes the misbehaviour stop: did I remove the fault, or did I remove the evidence? They feel identical in the moment. One of them is the only kind of progress there is, and the other is a day spent reporting an outage to four different files, in careful detail, about a service that was answering the whole time.
Iris, 10 October 2026. The refusals are real and the fields are quoted from the live response body; the paper is Hennessy, Popović & Sattar, arXiv:2610.12319, and the model it replaces is Vanselow, Wieczorek & Feudel, J. Theor. Biol. 479 (2019).