Back to blog
Engineering10 min read

Stop Sequences: How and When to Use Them

Stop sequences across OpenAI, Anthropic and Google, verified from each vendor's own API reference — exact field names, why OpenAI blocks stop on o3 and o4-mini, and when a schema beats it.

NH
Nafiul Hasan
Founder, Prompt Architects

TL;DR: A stop sequence is a string you send to a chat completion API that halts generation the moment the model outputs it, and every major vendor implements it as its own field: OpenAI's stop, Anthropic's stop_sequences, Google's stopSequences. It is reliable for cutting text off cleanly. It is the wrong tool for shaping structure, and OpenAI's own spec says its o3 and o4-mini reasoning models do not accept it at all.

Stop Sequences: How and When to Use Them

Stop sequences are one of the oldest generation controls in any LLM API, older than structured output and older than function calling, and they still sit in nearly every SDK's parameter list. The idea is simple: hand the model one or more strings, and the moment its output would contain one, the API cuts generation and returns whatever it produced up to that point. The matched string itself never makes it into the response.

What isn't simple is that "stop sequence" isn't one API contract shared across vendors. It's three, and they disagree on the field name, the documented cap on how many you can pass, and, on OpenAI's newest reasoning models, whether the parameter is honored at all. This page verifies each vendor's own field name and limit against their live API reference, then makes the harder case: for a lot of the jobs people reach for a stop sequence to do, it is quietly the wrong tool for the job.

What Is a Stop Sequence, Exactly?

A stop sequence is a plain string, or a short list of them, that you pass alongside your prompt. If the model's output ever matches one, the API stops generating right there and returns the text produced up to that point, with the matched sequence removed. It's a hard truncation rule enforced at the decoding layer, not a hint the model can weigh against its other instructions the way a system prompt is.

Every major vendor ships this control, but under a different name, in a different place, with a different documented limit:

VendorField nameWhere it livesDocumented limit
OpenAI (Chat Completions)stoprequest bodyup to 4 sequences
Anthropic (Messages API)stop_sequencesrequest bodyarray of strings, no documented cap
Google (Gemini API)stopSequencesinside generationConfigup to 5 sequences

Anthropic's own Messages API reference puts it plainly: "If you want the model to stop generating when it encounters custom strings of text, you can use the stop_sequences parameter." When a match fires, Anthropic's response carries a stop_reason of "stop_sequence" plus a separate stop_sequence field naming exactly which string matched, which is more diagnostic detail than either of the other two vendors returns.

How Do You Set One on Each Provider?

The field lives in a different place on each API, but the shape of the request is close enough that porting one to another is mostly a find-and-replace.

// OpenAI — Chat Completions
{
  "model": "gpt-4.1",
  "messages": [{ "role": "user", "content": "List exactly three colors:" }],
  "stop": ["\n\n", "4."]
}
// Anthropic — Messages API
{
  "model": "claude-opus-4-6",
  "max_tokens": 200,
  "messages": [{ "role": "user", "content": "List exactly three colors:" }],
  "stop_sequences": ["\n\n", "4."]
}
// Google — Gemini API
{
  "contents": [{ "parts": [{ "text": "List exactly three colors:" }] }],
  "generationConfig": {
    "stopSequences": ["\n\n", "4."]
  }
}

Google's own reference describes the field this way: "The set of character sequences (up to 5) that will stop output generation. If specified, the API will stop at the first appearance of a stop_sequence. The stop sequence will not be included as part of the response." Read literally, that's a hard cutoff on the first appearance, not the intended one, which matters more than it sounds like once you're matching against generated text you don't fully control.

Why Doesn't OpenAI's stop Parameter Work on Reasoning Models?

OpenAI's own public API specification describes the stop field's schema, named StopConfiguration, in two parts. The first is unusual as vendor documentation goes: "Not supported with latest reasoning models o3 and o4-mini." The second describes what the field does everywhere else it is accepted: "Up to 4 sequences where the API will stop generating further tokens. The returned text will not contain the stop sequence."

A flat, model-scoped rejection like that is rarer than the alternative, which is silence. Most parameter limitations on reasoning models show up as absence from a compatibility table or a passing mention buried in a guide, not as a sentence attached to the parameter's own schema naming the exact models it doesn't work on.

That contrast matters because the same specification doesn't do this anywhere else nearby. The definitions of frequency_penalty and presence_penalty, sitting a few lines above stop in the same request body, both read as plain range descriptions with no model carve-out attached. And OpenAI's reasoning guide, the page its own API reference points to for "the current state of unsupported parameters in reasoning models," contains zero mentions of either penalty parameter across the entire page. So stop's reasoning-model status is explicitly documented. Whether frequency or presence penalties do anything at all on o3 or o4-mini is not stated anywhere on OpenAI's side, in either direction. Don't assume a default; test it, and treat whatever you observe as unpublished behavior rather than a guaranteed contract.

Do Anthropic and Google Scope This the Same Way?

Neither vendor's own reference carries a comparable reasoning-model exception for its version of the parameter. Anthropic's Messages API reference documents stop_sequences once, with no model-specific carve-out, even though Claude ships its own extended-thinking models. Google's Gemini API reference does the same for stopSequences inside generationConfig.

Absence of a stated exception isn't the same claim as "this definitely works identically on every model" — a vendor's docs can simply not have caught up to a new release yet. But as written today, nothing on either reference limits the field the way OpenAI's StopConfiguration schema limits stop. If you're building against Claude's or Gemini's reasoning-capable models and a stop sequence silently stops mattering, that would currently be an undocumented behavior, not a documented one.

When Is a Stop Sequence the Wrong Tool?

A stop sequence solves exactly one problem: cutting text off at a literal string match. It has no notion that "well-formed JSON," "exactly three bullet points," or "no trailing explanation" are shapes rather than strings; it only knows the one sequence you gave it. Three failure patterns show up often enough to name directly.

It truncates instead of shaping. Passing } as a stop sequence to keep a model from rambling past a JSON object cuts the response at the first closing brace it produces, which is very often a nested object's closing brace, not the final one you wanted. The output isn't malformed prose you can eyeball and fix; it's a truncated document that fails to parse, which is a worse failure mode because it looks structural rather than obviously "the model kept going."

Here's what that looks like in practice. Say you ask a model to return one JSON object with a nested address field, and you pass } as a stop sequence to keep it from adding commentary afterward:

{
  "name": "Ada Lovelace",
  "address": {
    "city": "London"
  }

The stop sequence matched the closing brace of the nested address object, on the first occurrence, and generation ended there. The outer object was never closed. Nothing about that output looks like a model that misbehaved; it looks like a truncated file, and a downstream JSON parser reports a syntax error with no indication that a stop sequence, not the model, is what actually cut the string short. A schema-constrained response avoids this entirely because the model is constrained to emit a complete, valid structure or nothing at all, rather than being cut off partway through one by a string match that can't tell nested braces from outer ones.

It fires mid-token-stream, not mid-thought. Generation happens as tokens, and a stop sequence is checked against decoded text as it accumulates, not against any sense of "the model just finished its point." A sequence that matches earlier than you expected, whether from the "4.5 stars" case above or a stray occurrence of your own delimiter inside legitimate content, stops the response somewhere arbitrary relative to what you actually needed.

Structured output usually solves the underlying problem better. If what you actually want is "always valid JSON matching this shape" or "always exactly these five fields," a schema-constrained response enforces that shape at generation time, rather than truncating an unconstrained response after the fact. Structured output guarantees the schema; a stop sequence only guarantees that one string doesn't appear in the result, which is a much weaker property, and it's what people reach for stop to fake before finding the schema option in their own SDK. Prompt Architects' own JSON prompt workflows and the free JSON prompt generator exist because of exactly this gap: a schema constrains the shape once, up front, instead of hoping a delimiter never shows up where it shouldn't.

That framing generalizes past JSON. Whenever the actual requirement is "the output must look like X," reach for a schema first. Reach for a stop sequence only when the requirement genuinely is "don't let this literal string appear," full stop, with no shape guarantee attached. Our LLM parameter cheat sheet covers where structured-output fields live on each vendor's API if you're making that switch.

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 4.8★ on the Chrome Web Store.

Create An Account

So When Should You Actually Reach for a Stop Sequence?

A few jobs remain squarely stop-sequence shaped, because the requirement really is "cut here," not "produce this shape":

  • Simulating multi-turn dialogue in a single completion, stopping generation at your own turn marker (\nUser:, for example) so the model doesn't go on to write both sides of the conversation.
  • Capping a numbered or bulleted list at a known boundary, stopping before 6. when you've asked for five items and don't trust the model to stop counting on its own.
  • Cutting a completion-style prompt at a custom delimiter, the way few-shot examples separated by a marker string were handled before schema-constrained output existed as an option in most SDKs.
  • Preventing a model from continuing into a section header or delimiter that belongs to your own template, when the rest of that template gets assembled outside the model's response entirely.

Notice what all four share: the string being matched is either something you fully control, like your own delimiter, or a low-stakes boundary where a slightly early or slightly late cut costs nothing. That's the real dividing line, not "structured versus unstructured" content. If a mismatch would corrupt the thing you're building, that's the schema's job, not the stop sequence's. If a mismatch just means the delimiter fires one line later than ideal, a stop sequence is still the right, cheap tool, the same way chain-of-thought prompting is the right tool for reasoning depth and the wrong one for output formatting.

Frequently asked questions

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 4.8★ on the Chrome Web Store.

Create An Account