Finish-reason explainer
What each provider's stop or finish reason means and what to do about it — OpenAI, Anthropic, Gemini — and the one rule Salyro applies to it.
What it does
Every response says why the model stopped: finish_reason in Chat Completions, status and incomplete_details.reason in Responses, stop_reason at Anthropic, finishReason at Gemini. Pick where yours came from, type the value or pick it, and the explainer says:
- what it means, quoted from the provider's own page or schema;
- what to do about it, where the provider says — and
unknownwhere it does not; - whether the answer is whole — complete, cut short, a tool call, filtered, refused, paused or failed;
- what Salyro does with it.
Below, every documented value of the chosen format is listed in one table.
Try it: Chat Completions length, Anthropic refusal, or Gemini SAFETY.
Where the meanings come from
- Anthropic: its "Stop reasons and fallback" page on platform.claude.com, whose quick-reference table gives each value's meaning and what to do.
- OpenAI: its published OpenAPI description, which defines each
finish_reasonand each Responsesstatusandincomplete_details.reason. It says what a value means, not what to do, so "what to do" isunknown. Onlysteeredhas a description of its own among the incomplete reasons; the others are read by their names. - Gemini: the
Candidate.FinishReasonenum of Google's publishedgenerative_service.proto. It says what a value means, not what to do. - xAI: its page could not be read, so nothing is recorded. xAI speaks the Chat Completions format.
The outcome — complete, cut short and so on — is read from each value's meaning, so that a truncated answer is recognisable whichever provider sent it.
A value is matched exactly, case included: STOP is Gemini's and stop is OpenAI's.
Every value of every format, with its source, is in one table in LLM stop and finish reasons by provider.
What Salyro does with it
Salyro has one rule about a finish reason, and it is on /v1/responses: only a finish_reason of length — the model ran out of room — can end an answer incomplete. A streamed response then ends with response.incomplete instead of response.completed, whatever the answer holds. A response that is not streamed is incomplete only when the answer has text, and its message item is incomplete too. With empty text or only tool calls, it ends completed. With any other finish reason an answer is never incomplete. The rule is read from Salyro's own code.
An answer that is not streamed and has neither content nor tool calls is no answer to Salyro, whatever its finish reason. A refusal carried only in refusal and a thinking-only answer are examples. Salyro answers 502 provider_error instead, on both endpoints. A streamed answer with nothing in it still ends with its finish reason.
Everything else passes through. /v1/chat/completions carries finish_reason as its routing layer returns it, streamed or not, except for that 502, and Salyro keeps no mapping from one provider's values to another's. A Behavior run has no finish reason: its stream ends with response.completed.
What it does not know
- Values a provider added after the date shown. A value that is not listed may be newer than the reading.
- What to do, where the provider's page does not say — OpenAI's and Gemini's schemas do not.
- xAI's values. Its page could not be read.
FAQ
My answer ended with length — what now?
The model reached the output limit in the request. The answer is cut short: raise the limit, or ask for a shorter answer. Anthropic's page says the same of max_tokens: "Raise max_tokens or continue the response."
Is refusal an error?
No. Anthropic's page states that safety classifiers return it "as a normal HTTP 200 response, not an error". It says to read stop_details and retry on a fallback model.
Why is my Salyro Responses answer incomplete?
The provider stopped because it ran out of room — its finish_reason was length. That is the only reason Salyro marks a response incomplete. A response that is not streamed is marked only when the answer has text. With neither text nor tool calls, it is a 502 instead.
Sources
Anthropic's meanings are quoted from its stop-reasons page on platform.claude.com. OpenAI's are from its OpenAPI description (openai/openai-openapi) and Gemini's from Google's generative_service.proto (googleapis/googleapis), both on GitHub. Salyro's rule is from its shared package, the code the gateway applies it with.
Where the numbers come from
- Facts about models and providers that are not in that catalogue carry their own source and the date they were checked, and are shown as unknown where no reliable source exists.
