Skip to content
Insights · AI Agents

Name the stop the response carried

The model was supposed to finish. Name the stop reason, show a limit is not a finished turn, and show another request that stopped differently.

Scroll
AI AgentsOct 20, 202613 min readBy Salman Naqvi, Founder & CEO
Name the stop the response carried

The model was supposed to finish. Do not send the sentence, and do not start another request you will have to explain, until you can name the stop reason on that response, show whether the string you were about to send is a completed turn or a limit, and show a different request that stopped for a different reason. If the log does not store the field, write that, and do not guess it from the prose. Do not ask the model whether it finished. You will get a fluent answer about a response you still have not opened.

This is the field that says why generation stopped. It is not the identifier of the model that ran. Name the model the request hit is that string, and whether the string you sent was the string that came back. A model id is not a stop reason. It is not the tool. Name the tool the model called is the tool, the arguments, and whether it ran. A stop reason of tool use does not name the tool, and naming the tool does not tell you the stop reason on the turn after the tool returned. It is not the clock. Time the answer the customer waited is the duration and the timeout. A long wait can end on a completed turn. A short wait can end because the token budget ran out. It is not two answers to one question. When one question gets two answers is that pair. A stop reason does not say which sentence was right.

None of what follows is a rate for this product, and none of it is legal advice. The field values below are one vendor's current description of a successful response. The accuracies below that are a 2025 study of open models on two math sets, under a token budget. An open model on a math set is not a Claude call. A score in that table is not a share of your customers' requests. Do not ask the model to reconcile them.

Every successful Messages API response includes stop_reason. The handling page's list is seven values. end_turn means the model finished the turn. The page says to use the response. That is an instruction about this value. It is not a finding that the sentence is true. max_tokens means the response hit the max_tokens you set. The page says to raise the limit or continue. A truncated sentence is not a finished one. stop_sequence means the model emitted one of the sequences you supplied. The field to read for which one is stop_sequence, not stop_reason. tool_use means the model is calling a tool. The page says to run the tool and return the result, and that a server tool still missing its result completes in a later response. pause_turn means a server-tool loop hit its iteration limit. The page says to send the assistant content back to continue. refusal means the model declined. The page says to read stop_details and, if you want an answer, to retry on a fallback model. model_context_window_exceeded means the response filled the model's context window. The page says to treat that response as truncated (Anthropic, Stop reasons and fallback).

Those seven are not synonyms, and the page does not treat them as errors. An error is a failed request. stop_reason is why a successful response stopped. max_tokens is the ceiling you set. model_context_window_exceeded is the window the model ran out of. One is your parameter. The other is the model's limit. Raising max_tokens does not enlarge the window, and a window that filled is not the budget you chose. pause_turn is not tool_use. The loop stopped because it ran out of iterations. The tool, if one was named, is the other article. stop_sequence is not max_tokens. You asked for that stop. The budget stop is the one you did not ask to see in the middle of a sentence. end_turn is not refusal. A completed turn can still be wrong. A refusal is a decline, not a short answer.

A refusal is still HTTP 200. The refusals page shows a response with stop_reason refusal, an empty content list, and stop_details naming a category. In that example the usage is 412 input tokens and 0 output tokens, and the model string in the sample is an illustration. 412 is not 0. The sample's model string is not your request. The identifier, if you need it, is name the model the request hit. stop_details is null for every stop reason other than refusal. On a refusal it carries a category and an explanation. The explanation is for a person to read. The page says the text is not stable, so you display it and you do not parse it. category and explanation are both null when the refusal does not map to a named category, and that null is a normal permanent value, not a placeholder. recommended_model appears only when the request set fallbacks, and the page calls it a hint, not a guarantee. It is null otherwise. A hint is not the identifier you already logged (Anthropic, Refusals and fallback).

The billing column is not a severity column. The same page prints five categories and whether the request is billed before any output. cyber, no. bio, yes. frontier_llm, yes. reasoning_extraction, yes. general_harms, no. A yes is not a no. cyber is not general_harms, even though both print no. bio is not frontier_llm, even though both print yes. Five rows do not become a percentage. Benign work can land in any of them. The page says so on each row. A category is not a verdict that the customer was attacking you. A refusal can arrive before any output, or mid-stream after some. In either case the page says to treat partial output as incomplete and discard it. A half sentence with stop_reason refusal is not a draft you send.

Three different things get called a refusal, and the streaming page separates them. A streaming classifier sets stop_reason to refusal. An input or copyright check fails as a 400. The model itself can also write a refusal as ordinary text, with whatever stop_reason a normal completion carries. A paragraph that says the model cannot help, sitting under end_turn, is the third kind. It is not the first. A 400 is not a stop_reason at all. There is no field to name, because the request did not succeed. Do not record a 400 as refusal, and do not record an end_turn apology as a classifier. If you continue a conversation after a classifier refusal without resetting the context, the page says the next turns refuse too. Resetting the context is not the same act as retrying on another model. The page lists both. Doing one does not do the other (Anthropic, Handle streaming refusals).

A token budget that cuts a chain of thought off is a studied failure, and it is not this API. Yi Sun, Han Wang, Jiaqiang Li, Jiacheng Liu, Xiangyu Li, Hao Wen, Huiwen Zheng, Yan Liang, Yuanchun Li, and Yunxin Liu, at Tsinghua's Institute for AI Industry Research, test open models on GSM8K and MATH500 while limiting how many tokens the model may generate. The abstract says more than 25 models. The results table has 28 rows. More than 25 is their phrase. 28 is the row count. Do not replace the phrase with the count, and do not replace the count with the phrase. GSM8K's test split is 1,319 problems. The paper also calls GSM8K 8.5k grade-school questions, which is the whole set, not the test split. 8.5k is not 1,319. MATH500 is 500 problems. 500 is not 1,319. Neither is a share of your traffic (Sun et al., Time's Up).

They compare two ways of hitting the budget. Directly terminating sets the maximum new tokens and lets generation die there. Early stopping injects a concluding line 25 tokens before the budget, using the signal Time's Up, so the model writes a final answer from whatever it has. Finding 1 says early stopping improves accuracy on every combination of the two datasets and the three prompts they tried. On GSM8K, the effect on the accuracy the model eventually converges to is negligible. On MATH500, the difference can be up to 5%. Up to 5% is their bound on that gap. It is not a cell in the table, and negligible is not 5. 25 tokens of warning is not the budget. The table itself is only the directly terminating method, and only the step-by-step prompt. The other two prompts, coarse-to-fine and answer-and-verify, are not in that table. Do not cite a step-by-step cell as if it were one of the other prompts.

The budget on that table is 4,096 new tokens for the models that are not reasoning models, and both 4,096 and 8,192 for the reasoning models. The number in parentheses is the 8,192 setting. An arrow means that score still needs more tokens before it converges. It does not mean the parenthetical is always higher, and it does not mean the two numbers are the same kind of fact. Sky-T1 prints 96.4 and 96.4 on GSM8K, and 87.6 and 87.6 on MATH500, with no arrow. DRD-Qwen at 14B, the table's short name for the DeepSeek-R1-Distill-Qwen series, prints 92.0 on GSM8K at both budgets, and 78.6 (87.4) on MATH500, with an arrow. 78.6 is not 87.4. 92.0 is not 78.6. Gemma-2 at 2B prints 64.8 on GSM8K and 23.8 on MATH500. 64.8 is not 23.8. Llama-3.2 at 1B prints 48.8 and 26.6. 48.8 is not 26.6. Qwen-2.5 at 32B prints 95.9 and 81.0. 95.9 is not 81.0. 96.4 is not 64.8. None of these is a stop_reason, and none of them is a Claude id.

A prose estimate of how long some models take to converge, under the step-by-step prompt, is over 400 tokens on GSM8K and 1k tokens on MATH500, for QwQ, three Qwen-2.5 sizes, and Phi-4. Over 400 is not 1k. Neither is 4,096, and neither is the 25 tokens of warning. The decoding is zero-shot and greedy. The libraries are transformers 4.46.3 and vLLM 0.6.3.post1. A version pin is not an accuracy. These models are not the Messages API, so they do not carry end_turn or max_tokens. What they carry is the lesson the field is for: a chain that dies at the budget is not the chain the model would have finished, and an answer extracted from the stump is not the answer you should send. The paper's early-stopping line is a research procedure. It is not a substitute for reading stop_reason on the response you actually got.

Do the three proofs on one real response, in the log that actually stored it. First, the field. Copy stop_reason, and copy stop_sequence and stop_details when they are present. If the log kept the text and dropped the field, write that the field was not stored. Do not infer end_turn because the sentence has a period. Second, the kind of stop. If the value is max_tokens, or model_context_window_exceeded, the text is truncated. Do not send it as the answer. If the value is refusal, discard any partial text, and do not continue that context as if the turn had completed. If the value is tool_use, you have not finished. The tool page is the next proof, and this field only told you a tool was the reason the turn paused. If the value is end_turn, you may read the text. You have not yet shown it is right. Third, the other request. A different call, the same day, stopped for a different reason, or you write that every stored response has the same value. One value on one row is a fact. It is not a distribution. If you cannot find a second row because the log keeps one field for the whole day, write that.

Three moves feel like the proof and are a second problem. Asking the model whether it finished. Lengthening max_tokens and sending the new sentence without reading the new stop reason. You have a second response. You have not shown the first one was truncated, and you have not shown the second one completed. Treating a model-written apology, under end_turn, as a classifier refusal, or treating a 400 as a stop reason. The streaming page already separates those three. A user text that replaced the instruction is when the user rewrote the rule. The stop reason does not tell you the instruction lost. It tells you why the tokens ended.

The shape of a product that can refuse to send a stump, without refusing every answer, is narrower than a benchmark. The support agent we shipped for a DTC brand answers order status, returns, and product questions from order data, policies, and the catalog, and it can look up an order, start a return, or change an address behind a permission check, with escalation to a person. It is not a stop-reason study. Nothing in that description is a headcount, a duration, or a result figure. The shape is the split: a lookup that ended on end_turn can be read, and a lookup that ended on max_tokens is not an order status you tell the customer. A design that stores the prose and drops the field cannot make that split.

There is a version of this response where hiring the path is the wrong purchase. Nothing is in production. No model is being called, so there is no field to read. The user sent two questions and got two answers. That is when one question gets two answers, and it is not a truncated turn. A customer has already seen another customer's data. A stop reason does not close a leak. The wrong value was already a write. The field tells you why the tokens ended. It does not undo the row. Or no metric was ever named, so there is nothing a later eval can fail. The questions for that gap are not this page.

When the response is real and the field is not in the log, the missing object is specific. stop_reason on that call, the distinction between a completed turn and a limit, and one other call whose reason you can also name. An AI pilot failed to reach production engagement is for the system that is already in front of customers and cannot yet show those three: audit in the first one to two weeks, finished in 8–12 weeks, scoped after the audit, unpaid if the agreed metric does not move, rollout behind a human-review gate. The triple you wrote tonight is the kind of case the harness has to include, or the next release will be just as fluent and just as cut off. The harness is AI evaluation and observability. An AI integration sprint is the shape where the acceptance sentence can require the field on every stored response. If you do not yet know whether the pilot can be saved, a two-week AI readiness assessment hands you the findings either way. Those are the terms on the site. They are not a promise that every short answer was max_tokens, and they are not a rate. Up to 5% is one paper's bound on a math set. 0 output tokens is one documentation example. Neither is your log.

A hostname a customer attached, and a check a merge was waiting on, are different objects: show the name their domain points at and name the check the merge required. Do not record either on this page. A DNS target is not a stop reason. A status check is not a model response.

The temperature on the request is a different field from the reason the tokens ended: which temperature did that call use?. A stop reason does not say how the draw was scaled. A temperature is not end_turn.

Before you send the sentence, do the three proofs and write the field. Name the stop reason, or write that it was not stored. Show a limit is not a finished turn. Show another request that stopped for a different reason. Do not ask the model whether it was done, and do not treat a period at the end of a stump as end_turn. The prose is what they would have read. The field is the page you can defend.

Find this useful? Tell Google to show you more of it.

Let's put AI to work in your business.

A 30-minute call. You bring the workflow or the roadmap — we'll tell you what's feasible, what it costs, and what we'd build first.

Book a call→