Before the stream
Validation, auth, and capacity are checked up front. These are ordinary JSON responses with a 4xx status. No credit is charged.
On the stream
Anything that goes wrong during generation arrives as a terminal
error event, after HTTP 200 has already been sent. Whether a credit was charged depends on the code.Shape
Rejections before the stream:code. The message is for humans and may be reworded.
Before the stream
rate_limited has two causes with the same code: the per-key call budget and the per-workspace concurrency limit. Either way it’s safe to retry after a short wait, and nothing has been charged. See Credits and limits.On the stream
Handling them
The main thing to get right is handling the two places separately:rate_limited automatically with backoff, retry generation_failed once, look for the email before retrying timed_out, and never retry the 400s or 401s, because they’ll fail the same way until you change something.
Over MCP
MCP tools don’t return codes. A failed tool call comes back as an error result whose text is meant for the assistant to read and act on, and most assistants relay it to you. The common ones:
An expired OAuth sign-in isn’t a tool error. Your client receives HTTP 401 and refreshes on its own, or asks you to sign in again.