Prompt Recipes
Roo Iyer6 min read3 views

Stop Sequences: 4 Recipes That Ship (2026)

Stop sequences in 2026: four copy-paste recipes that cut a model off at a delimiter, bound a JSON object, force one section, and stop an agent from faking its own turn, plus where they break.

A single yellow vertical bar halting a horizontal stream of grey dots at a hard boundary, on a stark white minimalist poster.
A single yellow vertical bar halting a horizontal stream of grey dots at a hard boundary, on a stark white minimalist poster.
On this page

Quick Answer

A stop sequence is a hard boundary, not a polite request. You pass stop_sequences an array of strings; the moment the model generates one, generation halts. On Claude the response comes back with stop_reason: "stop_sequence" and a stop_sequence field naming which string fired. The trigger text is NOT in the output. In 2026 this is the cheapest way to cut a model off at a delimiter, bound a JSON object, or stop an agent from hallucinating its own next turn. Four copy-paste recipes below.

A stop sequence is a contract with the decoder, not an instruction in the prompt. "Please stop after the JSON" is a suggestion the model can ignore. stop_sequences: ["}"] is enforced at generation time. Anthropic logo Anthropic documents the behavior under stop reasons and fallback; the recipes here are written for the Messages API and ship as-is.

Recipe 1: Cut the model off at a delimiter

Claim. Stop on the closing fence and you never pay for the essay after the code block.

Receipt.

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 800,
  "stop_sequences": ["```"],
  "messages": [
    {"role": "user", "content": "Write a Python function to slugify a string. Code only, in a fenced block."},
    {"role": "assistant", "content": "```python\n"}
  ]
}

The model writes the function and halts the instant it emits the closing fence. stop_reason is stop_sequence. No "here is how it works" paragraph after.

Why it works. The decoder checks each new chunk against your strings. Match found, generation ends. The prompt never has to beg.

Failure mode. The closing fence is consumed, not returned. Re-append it before you parse, or your Markdown block is unbalanced.

Recipe 2: Bound a JSON object

Claim. Prefill {, stop on }, and you get exactly one object with zero trailing chatter.

Receipt.

json
{
  "model": "claude-haiku-4-5",
  "max_tokens": 400,
  "stop_sequences": ["}"],
  "messages": [
    {"role": "user", "content": "Return {city, country} for the capital of Japan."},
    {"role": "assistant", "content": "{"}
  ]
}

Reply: "city": "Tokyo", "country": "Japan". Prepend the { you sent, append the } that fired the stop, and you have valid JSON on the first call. This pairs directly with assistant prefill; for nested schemas see the structured-output recipes.

Why it works. Prefill forces the open brace. The stop sequence forces the close. The model has no room to add notes.

Failure mode. A single } fires on the FIRST closing brace, so nested objects truncate early. For nested JSON, drop the stop and validate the parse instead.

Recipe 3: Force one section at a time

Claim. Stop at the next header and the model emits exactly one block, not the whole document.

Receipt.

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 500,
  "stop_sequences": ["\n## "],
  "messages": [
    {"role": "user", "content": "Write the '## Summary' section of a release note for v2.1."}
  ]
}

You get the Summary and nothing else. Loop with the next header to stream a doc section by section, each call cheap and boundable.

Why it works. \n## is the exact string the model emits before a new heading. Catching it ends the turn on the section boundary.

Failure mode. If the model never reaches a second header it runs to max_tokens. Always set max_tokens as the backstop.

Recipe 4: Stop an agent inventing its own turn

Claim. In a ReAct or tool loop, stop before the model writes the observation it has not actually run yet.

Receipt.

json
{
  "model": "claude-sonnet-5",
  "max_tokens": 512,
  "stop_sequences": ["\nObservation:"],
  "messages": [
    {"role": "user", "content": "Question: What is the population of Oslo?\nThought:"}
  ]
}

The model writes its Thought and Action, then halts at \nObservation: so YOUR code runs the tool and supplies the real result. Without the stop, the model hallucinates the observation and reasons on fiction.

Why it works. The stop sequence hands control back to your orchestrator at the exact token the model would otherwise use to fake the environment.

Failure mode. Frameworks sometimes drop the parameter before it reaches the API and the loop breaks silently, a real Claude and CrewAI bug filed in late 2025. Log stop_reason on every call; if it is end_turn when you expected stop_sequence, your stop never arrived.

Where stop sequences break

Five hard edges. Learn them before you ship.

  • The trigger is consumed, not returned. Anthropic logo Claude strips the matched string from the output and reports it in the stop_sequence field. If your parser needs it, re-append it.
  • Whitespace and tokenization cause silent misses. A stop string that does not align to how the model actually emits text can be skipped. "Stop sequences being ignored" is the classic bug report. Match on strings the model really produces (a bare }), not on hopeful spacing (" }").
  • Provider parameter names differ. OpenAI logo Anthropic uses stop_sequences (an array). OpenAI's API uses stop, a string or an array of up to four in 2026. Same idea, different key. Copy a Claude call into a GPT client without renaming the field and no stop fires.
  • Streaming still works, but check the event. You get partial deltas then a stop event; the trigger text will not appear in the stream. Read stop_reason from the final message, not the chunks.
  • Do not confuse it with stop_reason. stop_sequences is your input array. stop_reason is the model's output telling you why it halted (end_turn, max_tokens, stop_sequence, tool_use). Branch on the output; never assume your stop is the reason it ended.

A stop sequence is not a prompt trick. It is a kill switch on the decoder. Put it exactly where the answer should end.

FAQ

What is a stop sequence?
A stop sequence is a string you pass to the API that ends generation the moment the model produces it. On Claude you set stop_sequences to an array; when one matches, the model stops and stop_reason becomes stop_sequence.

Is the stop sequence included in the output?
No. On the Claude Messages API the matched string is removed from the returned text and reported separately in the stop_sequence field. Re-append it yourself if your parser expects it.

Why is my stop sequence being ignored?
Usually the string never matches what the model actually emits, often because of extra whitespace, or a framework dropped the parameter before the API call. Match on exact emitted text and log stop_reason to confirm the stop reached the model.

What is the difference between stop_sequences and stop_reason?
stop_sequences is the input list of strings that should halt generation. stop_reason is the output field explaining why the model stopped, one of end_turn, max_tokens, stop_sequence, or tool_use.

How many stop sequences can I use?
Keep the list small and precise. OpenAI's stop parameter accepts up to four sequences in 2026. Anthropic accepts an array; a handful of exact strings beats a long fuzzy list.

Do stop sequences work with streaming?
Yes. Generation still halts at the trigger, but the trigger text will not appear in the streamed deltas. Read the final message's stop_reason rather than inspecting chunks.

Cost to test: $0.03 (all four recipes on Haiku 4.5 and Sonnet 5, well under a dozen calls).

R

Written by

Roo Iyer

Roo Iyer writes tested, no-preamble prompt and API recipes for PromptAttic. Every recipe ships with a receipt and a cost to test.

FAQ

What is a stop sequence?

A stop sequence is a string you pass to the API that ends generation the moment the model produces it. On Claude you set stop_sequences to an array; when one matches, the model stops and stop_reason becomes stop_sequence.

Is the stop sequence included in the output?

No. On the Claude Messages API the matched string is removed from the returned text and reported separately in the stop_sequence field. Re-append it yourself if your parser expects it.

Why is my stop sequence being ignored?

Usually the string never matches what the model actually emits, often because of extra whitespace, or a framework dropped the parameter before the API call. Match on exact emitted text and log stop_reason to confirm the stop reached the model.

What is the difference between stop_sequences and stop_reason?

stop_sequences is the input list of strings that should halt generation. stop_reason is the output field explaining why the model stopped, one of end_turn, max_tokens, stop_sequence, or tool_use.

How many stop sequences can I use?

Keep the list small and precise. OpenAI's stop parameter accepts up to four sequences in 2026. Anthropic accepts an array; a handful of exact strings beats a long fuzzy list.

Do stop sequences work with streaming?

Yes. Generation still halts at the trigger, but the trigger text will not appear in the streamed deltas. Read the final message's stop_reason rather than inspecting chunks.