Skip to content
Salyro
Reference

LLM stop and finish reasons by provider

Every finish and stop reason OpenAI, Anthropic and Gemini document, what each means and what to do, with its source, and what Salyro does with it.

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. When Gemini blocks a prompt before answering, the reason is in promptFeedback.blockReason instead. The table has one row for each value a provider documents, in each of those formats. Each row gives the value exactly as a response carries it, what it means, what to do about it, and whether the answer is whole: complete, cut short, a tool call, filtered, refused, paused or failed.

Where the rows come from

Each meaning is quoted from the provider's own page or schema, and the Source column gives that page and the day it was read.

  • Anthropic: its stop-reasons page on platform.claude.com, which also says what to do about each value.
  • OpenAI: its published OpenAPI description on GitHub. It says what a value means, not what to do.
  • Gemini: the FinishReason and BlockReason enums of Google's published generative_service.proto on GitHub. It says what a value means, and what to do only about a blocked prompt.

The outcome is read from each value's meaning, so a cut-short answer can be found whichever provider sent it. These are the same facts the finish-reason explainer reads. To look up one value and see what Salyro does with it, use the explainer.

The rows marked Salyro come from Salyro's own code, not from a provider. Salyro has one rule about a finish reason: on /v1/responses, only a finish_reason of length can end an answer incomplete. How it applies depends on whether the answer is streamed:

  • Streamed: length ends the stream with response.incomplete instead of response.completed, whatever the answer holds.
  • Not streamed: the response is incomplete only when the answer has text. Its message item is then incomplete too. An answer cut short with empty text or only tool calls has no message item, so it ends completed.

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, an empty message and a thinking-only answer are all examples. Salyro drops it and answers 502 provider_error instead, on /v1/responses and /v1/chat/completions alike. A streamed answer with nothing in it still ends with its finish reason.

With every other value, an answer with something in it ends completed, streamed or not. Otherwise the value passes through: /v1/chat/completions carries finish_reason as Salyro's routing layer returns it, except for that 502, and Salyro keeps no mapping from one provider's values to another's. So the Through Salyro column gives no Chat Completions value for an Anthropic or Gemini reason. It says the mapping is unknown.

How often it is checked

Every fact has the day it was read. Each is due to be read again 90 days later, and Salyro's data report lists every fact with its re-check date. A fact past its date is flagged, not removed. Who re-reads the pages, and whether 90 days is the right interval, is still an open decision. A change to the data changes this table the next time the site is built. Nothing in the table is typed by hand.

What it does not know

  • xAI's values. Its page could not be read, so its row says unknown rather than listing values from memory. xAI speaks the Chat Completions format.
  • What to do, where the provider does not say. OpenAI's schema and Gemini's enum give meanings only, so What to do is unknown on their rows. It is not filled in with advice.
  • Values added after the day shown. A value missing from the table may be newer than the reading.
  • OpenAI's own guides. They could not be read from the build. Only the published schema was.

Search by value or meaning, filter by format or outcome, sort by any column, and download the rows you see as CSV. Each row has its own link: select the value.

50 rows

Every finish and stop reason each provider documents, what it means and what to do, and what Salyro does with it
stopOpenAI Chat Completionsfinish_reasonCompleteThe model hit a natural stop point or a provided stop sequence.unknown/v1/chat/completions carries it as Salyro’s routing layer returns it — except that an answer that is not streamed, with neither content nor tool calls, is answered with provider_error (HTTP 502) instead. On /v1/responses, with this finish_reason, a streamed answer ends completed, whatever it holds; one that is not streamed ends completed when it has text, empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L42723 (read 2026-09-26)
lengthOpenAI Chat Completionsfinish_reasonCut shortThe maximum number of tokens specified in the request was reached.unknown/v1/chat/completions carries it as Salyro’s routing layer returns it — except that an answer that is not streamed, with neither content nor tool calls, is answered with provider_error (HTTP 502) instead. On /v1/responses, with this finish_reason, a streamed answer ends incomplete, whatever it holds; one that is not streamed ends incomplete when it has text and completed when it has empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L42723 (read 2026-09-26)
content_filterOpenAI Chat Completionsfinish_reasonFilteredContent was omitted due to a flag from OpenAI's content filters.unknown/v1/chat/completions carries it as Salyro’s routing layer returns it — except that an answer that is not streamed, with neither content nor tool calls, is answered with provider_error (HTTP 502) instead. On /v1/responses, with this finish_reason, a streamed answer ends completed, whatever it holds; one that is not streamed ends completed when it has text, empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L42723 (read 2026-09-26)
tool_callsOpenAI Chat Completionsfinish_reasonTool callThe model called a tool.unknown/v1/chat/completions carries it as Salyro’s routing layer returns it — except that an answer that is not streamed, with neither content nor tool calls, is answered with provider_error (HTTP 502) instead. On /v1/responses, with this finish_reason, a streamed answer ends completed, whatever it holds; one that is not streamed ends completed when it has text, empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L42723 (read 2026-09-26)
function_callOpenAI Chat Completionsfinish_reasonTool callThe model called a function (deprecated).unknown/v1/chat/completions carries it as Salyro’s routing layer returns it — except that an answer that is not streamed, with neither content nor tool calls, is answered with provider_error (HTTP 502) instead. On /v1/responses, with this finish_reason, a streamed answer ends completed, whatever it holds; one that is not streamed ends completed when it has text, empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L42723 (read 2026-09-26)
completedOpenAI Responsesstatus · incomplete_details.reasonCompleteThe response generation completed.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L67442 (read 2026-09-26)
incompleteOpenAI Responsesstatus · incomplete_details.reasonCut shortThe response finished as incomplete; `incomplete_details.reason` says why.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L68563 (read 2026-09-26)
failedOpenAI Responsesstatus · incomplete_details.reasonFailedThe response failed.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L67936 (read 2026-09-26)
cancelledOpenAI Responsesstatus · incomplete_details.reasonFailedThe response was cancelled.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L66896 (read 2026-09-26)
in_progressOpenAI Responsesstatus · incomplete_details.reasonNot finished yetThe response is still being generated.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L68499 (read 2026-09-26)
queuedOpenAI Responsesstatus · incomplete_details.reasonNot finished yetThe response is queued and has not started.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L66896 (read 2026-09-26)
max_output_tokensOpenAI Responsesstatus · incomplete_details.reasonCut shortIncomplete: the response reached its output token limit.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L66951 (read 2026-09-26)
content_filterOpenAI Responsesstatus · incomplete_details.reasonFilteredIncomplete: content was withheld by a content filter.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L66953 (read 2026-09-26)
max_messagesOpenAI Responsesstatus · incomplete_details.reasonCut shortIncomplete: the response reached a limit on the number of messages.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L66952 (read 2026-09-26)
steeredOpenAI Responsesstatus · incomplete_details.reasonOtherIncomplete: over WebSocket, the response stopped at a safe output boundary after a `response.steer` event.unknownNot passed through: Salyro’s /v1/responses sets its own status from the finish_reason (see Salyro’s rows) and sends no incomplete_details.github.com/openai/openai-openapi/blob/42eccf12b80a8aecb5a457060d6b17e6f1f84b8d/openapi.yaml#L66937 (read 2026-09-26)
end_turnAnthropic Messagesstop_reasonCompleteClaude finished its response naturally.Use the response.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
max_tokensAnthropic Messagesstop_reasonCut shortThe response reached your `max_tokens` limit.Raise `max_tokens` or continue the response.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
stop_sequenceAnthropic Messagesstop_reasonCompleteClaude emitted one of your `stop_sequences`.Read `stop_sequence` to see which one fired.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
tool_useAnthropic Messagesstop_reasonTool callClaude is calling a tool.Run the tool and return the result. A server tool call still missing its result block completes in a later response.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
pause_turnAnthropic Messagesstop_reasonPausedA server-tool loop reached its iteration limit.Send the assistant content back to continue.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
refusalAnthropic Messagesstop_reasonRefusedClaude declined to respond.Read `stop_details` and retry on a fallback model.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
model_context_window_exceededAnthropic Messagesstop_reasonCut shortThe response filled the model's context window.Treat the response as truncated.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.platform.claude.com/docs/en/build-with-claude/handling-stop-reasons (read 2026-09-26)
FINISH_REASON_UNSPECIFIEDGeminifinishReasonUnspecifiedDefault value. This value is unused.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L691 (read 2026-09-26)
STOPGeminifinishReasonCompleteNatural stop point of the model or provided stop sequence.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L694 (read 2026-09-26)
MAX_TOKENSGeminifinishReasonCut shortThe maximum number of tokens as specified in the request was reached.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L697 (read 2026-09-26)
SAFETYGeminifinishReasonFilteredThe response candidate content was flagged for safety reasons.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L700 (read 2026-09-26)
RECITATIONGeminifinishReasonFilteredThe response candidate content was flagged for recitation reasons.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L703 (read 2026-09-26)
LANGUAGEGeminifinishReasonFilteredThe response candidate content was flagged for using an unsupported language.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L707 (read 2026-09-26)
OTHERGeminifinishReasonOtherUnknown reason.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L710 (read 2026-09-26)
BLOCKLISTGeminifinishReasonFilteredToken generation stopped because the content contains forbidden terms.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L713 (read 2026-09-26)
PROHIBITED_CONTENTGeminifinishReasonFilteredToken generation stopped for potentially containing prohibited content.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L716 (read 2026-09-26)
SPIIGeminifinishReasonFilteredToken generation stopped because the content potentially contains Sensitive Personally Identifiable Information (SPII).unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L720 (read 2026-09-26)
MALFORMED_FUNCTION_CALLGeminifinishReasonFailedThe function call generated by the model is invalid.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L723 (read 2026-09-26)
IMAGE_SAFETYGeminifinishReasonFilteredToken generation stopped because generated images contain safety violations.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L727 (read 2026-09-26)
IMAGE_PROHIBITED_CONTENTGeminifinishReasonFilteredImage generation stopped because generated images has other prohibited content.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L731 (read 2026-09-26)
IMAGE_OTHERGeminifinishReasonOtherImage generation stopped because of other miscellaneous issue.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L734 (read 2026-09-26)
NO_IMAGEGeminifinishReasonFailedThe model was expected to generate an image, but none was generated.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L737 (read 2026-09-26)
IMAGE_RECITATIONGeminifinishReasonFilteredImage generation stopped due to recitation.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L740 (read 2026-09-26)
UNEXPECTED_TOOL_CALLGeminifinishReasonFailedModel generated a tool call but no tools were enabled in the request.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L743 (read 2026-09-26)
TOO_MANY_TOOL_CALLSGeminifinishReasonFailedModel called too many tools consecutively, thus the system exited execution.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L747 (read 2026-09-26)
BLOCK_REASON_UNSPECIFIEDGemini, prompt blockedpromptFeedback.blockReasonUnspecifiedDefault value. This value is unused.unknownA Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L598 (read 2026-09-26)
SAFETYGemini, prompt blockedpromptFeedback.blockReasonFilteredPrompt was blocked due to safety reasons. Inspect `safety_ratings` to understand which safety category blocked it.Rephrase the prompt.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L602 (read 2026-09-26)
OTHERGemini, prompt blockedpromptFeedback.blockReasonFilteredPrompt was blocked due to unknown reasons.Rephrase the prompt.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L605 (read 2026-09-26)
BLOCKLISTGemini, prompt blockedpromptFeedback.blockReasonFilteredPrompt was blocked due to the terms which are included from the terminology blocklist.Rephrase the prompt.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L609 (read 2026-09-26)
PROHIBITED_CONTENTGemini, prompt blockedpromptFeedback.blockReasonFilteredPrompt was blocked due to prohibited content.Rephrase the prompt.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L612 (read 2026-09-26)
IMAGE_SAFETYGemini, prompt blockedpromptFeedback.blockReasonFilteredCandidates blocked due to unsafe image generation content.Rephrase the prompt.A Salyro caller does not receive this field: Salyro answers with the finish_reason its routing layer returns. Salyro keeps no mapping from this value to a finish_reason, so which one it becomes is unknown.github.com/googleapis/googleapis/blob/5174d7c27d275560a3c963d41c3911d0a060a207/google/ai/generativelanguage/v1beta/generative_service.proto#L615 (read 2026-09-26)
unknownxAIfinish_reasonunknownxAI's API reference is blocked by this build's network egress and was not read. xAI speaks the Chat Completions format, but which `finish_reason` values it sends, and what each means, is not recorded until somebody reads its page.unknownA Chat Completions finish_reason: carried as Salyro’s routing layer returns it. Only length can end a /v1/responses answer incomplete (see Salyro’s rows).docs.x.ai/docs/api-reference (tried, not read, 2026-09-26)
lengthSalyro /v1/responses, streamedstatusCut shortA finish_reason of length — the model ran out of room: a streamed answer ends incomplete, whatever it holds. Its stream ends with response.incomplete.unknownThe one rule Salyro has about a finish reason, applied to the stream as a whole: length → incomplete.Salyro’s code: responseStatusForFinishReason in @salyro/types, and how /v1/responses applies it
lengthSalyro /v1/responses, not streamedstatusCut shortA finish_reason of length: a response that is not streamed ends incomplete when it has text and completed when it has empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.unknownThe response’s status follows its message item, which is incomplete for length — and there is a message item only when the answer has text. A cut-short answer with no text is not marked incomplete. An answer with neither content nor tool calls — a refusal carried only in refusal, say — is no answer to Salyro, whatever its finish reason: “The upstream model provider returned no completion.”Salyro’s code: responseStatusForFinishReason in @salyro/types, and how /v1/responses applies it
any other valueSalyro /v1/responsesstatusDepends on the valueEvery other finish_reason, whatever the provider meant by it: a streamed answer ends completed, whatever it holds; one that is not streamed ends completed when it has text, empty text or only tool calls; with neither content nor tool calls, Salyro answers provider_error (HTTP 502) instead.unknownPassed through otherwise: /v1/chat/completions carries it as Salyro’s routing layer returns it — except that an answer that is not streamed, with neither content nor tool calls, is answered with provider_error (HTTP 502) instead. Salyro keeps no mapping from one provider’s values to another’s.Salyro’s code: responseStatusForFinishReason in @salyro/types, and how /v1/responses applies it

Where the rows come from