refusals-and-fallback changedbuild-with-claude/refusals-and-fallback
Nearest release: v2.1.307, published an hour after this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Recorded here
Lines+23added
Lines−23removed
From line
10
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits23to this page, all time
The whole hunk
from line 10, old and new numbered
/
from line 10
1010
1111Related pages:
1212
13* [Stop reasons and fallback](https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons): the full list of `stop_reason` values.
14* [Fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit): how to avoid paying the prompt-cache cost twice when you build the retry yourself.
15* [SDK middleware](https://platform.claude.com/docs/en/cli-sdks-libraries/middleware): the SDK helper that wraps all of this.
16* [Fallback and billing cookbook](https://platform.claude.com/cookbook/fable-5-fallback-billing-guide): a worked end-to-end example.
13* [Stop reasons and fallback](https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons): the full list of `stop_reason` values
14* [Fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit): how to avoid paying the prompt-cache cost twice when you build the retry yourself
15* [SDK middleware](https://platform.claude.com/docs/en/cli-sdks-libraries/middleware): the SDK helper that wraps all of this
16* [Fallback and billing recipe](https://platform.claude.com/cookbook/fable-5-fallback-billing-guide): a worked end-to-end example
1717
1818The simplest setup, in beta on the Claude API: set `fallbacks` to `"default"`, and the API retries a declined request on the fallback model Anthropic recommends for its refusal category. For categories with no recommended fallback, the refusal stands. Claude Haiku 5.5 has no server-side fallback, so for it use [client-side fallback with the SDK middleware](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#client-side-fallback) or [write the retry yourself](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#manual-retry).
1919
from line 135
135135 client = Anthropic::Client.new
136136
137137 response = client.beta.messages.create(
138 model: "claude-fable-5",
138 model: Anthropic::Model::CLAUDE_FABLE_5,
139139 max_tokens: 1024,
140140 messages: [{role: "user", content: "Hello, Claude"}],
141141 fallbacks: :default,
from line 451
451451 client = Anthropic::Client.new
452452
453453 response = client.beta.messages.create(
454 model: "claude-fable-5",
454 model: Anthropic::Model::CLAUDE_FABLE_5,
455455 max_tokens: 1024,
456456 messages: [{role: "user", content: "Hello, Claude"}],
457457 fallbacks: :default,
from line 470
470470 ```
471471</CodeGroup>
472472
473Anthropic sets safeguards for each model individually and for each policy category, in line with the model's capability: depending on the category, a flagged request may fall back to a less capable model or be declined. The `"default"` mode encodes these per-model, per-category recommendations for you, so a refused request is retried on the model Anthropic recommends for that category. Fallbacks are visible either way: the response names the model that served it, and the `fallback` content block marks the handoff.
473Anthropic sets safeguards for each model individually and for each policy category, in line with the model's capability: depending on the category, a flagged request might fall back to a less capable model or be declined. The `"default"` mode encodes these per-model, per-category recommendations for you, so a refused request is retried on the model Anthropic recommends for that category. Fallbacks are visible either way: the response names the model that served it, and the `fallback` content block marks the handoff.
474474
475The routing is applied server-side and is not published per model on the [Models API](https://platform.claude.com/docs/en/api/models/list). To see which model served a refused request, check the response's top-level `model` field and look for a `fallback_message` entry in `usage.iterations`, as this page's samples do.
475The routing is applied server-side and is not published for each model on the [Models API](https://platform.claude.com/docs/en/api/models/list). To see which model served a refused request, check the response's top-level `model` field and look for a `fallback_message` entry in `usage.iterations`, as this page's samples do.
476476
477477Only a safety classifier decline triggers the fallback. A rate limit, overload, or server error on the requested model is returned to you as-is.
478478
from line 610
610610 client = Anthropic::Client.new
611611
612612 response = client.beta.messages.create(
613 model: "claude-fable-5",
613 model: Anthropic::Model::CLAUDE_FABLE_5,
614614 max_tokens: 1024,
615615 messages: [{role: "user", content: "Hello, Claude"}],
616 fallbacks: [{model: "claude-opus-4-8"}],
616 fallbacks: [{model: Anthropic::Model::CLAUDE_OPUS_4_8}],
617617 betas: ["server-side-fallback-2026-07-01"]
618618 )
619619
from line 624
624624A few rules apply to the `fallbacks` list:
625625
626626* Entries are tried in order. Each must be distinct from the other entries and from the requested model.
627* Each entry must be one of the requested model's permitted targets. With the beta header set, that list is published as `allowed_fallback_models` on the model's entry in the [Models API](https://platform.claude.com/docs/en/api/beta/models/list).
627* Each entry must be one of the requested model's permitted targets. With the beta header set, that list is published as `allowed_fallback_models` on the [model's entry in the Models API](https://platform.claude.com/docs/en/api/beta/models/list).
628628* Each entry names a `model` and can override `max_tokens`, `thinking`, `output_config`, and `speed` for that attempt only.
629629* The request must be valid as a direct request to every model named. If a fallback model does not support a feature the request uses, the API rejects the request up front. Under the `2026-07-01` header, `thinking: {"type": "between_tools"}` is the exception: when a Claude Sonnet 5.5 request falls back to Claude Sonnet 5, the fallback attempt runs with `thinking: {"type": "disabled"}` and `display: "omitted"`. Under `2026-06-01`, set `thinking` on the Claude Sonnet 5 entry, or the request is rejected up front.
630630* As with the default mode, only a safety classifier decline triggers the fallback. A rate limit, overload, or server error on the requested model is returned to you as-is.
from line 711
711711
712712### Streaming
713713
714On a streaming request, the retry happens on the same stream, and nothing you have already received is invalidated. What you see depends on when the decline happens.
714On a streaming request, the retry occurs on the same stream, and nothing you have already received is invalidated. What you see depends on when the decline occurs.
715715
716**When the decline happens before any output:**
716**When the decline occurs before any output:**
717717
718718* `message_start` names the fallback model, and the `fallback` block is the first content block.
719719* Because `message_start` waits for the fallback attempt to start, time to first byte includes the declined attempt.
720720
721**When the decline happens mid-output:**
721**When the decline occurs mid-output:**
722722
723723* The open content block closes, and the `fallback` block (an ordinary `content_block_start` and `content_block_stop` pair with no deltas) marks the boundary.
724724* The fallback model continues from the partial output. Only the partial output's `text` blocks are passed to the fallback model as context. Other block types remain in `content`.
from line 726
726726
727727### Non-streaming responses
728728
729On a non-streaming request, a mid-output decline behaves differently: the response omits the declined model's partial output, and the fallback model answers from scratch. The result looks like a decline before any output, with the `fallback` block first. The declined attempt and its output tokens still appear in `usage.iterations`.
729On a non-streaming request, a mid-output decline behaves differently: the response omits the declined model's partial output, and the fallback model answers from the beginning. The result looks like a decline before any output, with the `fallback` block first. The declined attempt and its output tokens still appear in `usage.iterations`.
730730
731731<Note>
732732 **Declines during tool use:** completed tool work does not block fallback. When a decline fires after server tools (for example, web search or code execution) have finished executing within a request, the fallback attempt proceeds: the completed tool results carry over, and the fallback model can keep invoking server tools. The one case that does not retry is a streaming decline that fires while a tool-use block of any type (a client tool, a server tool, or an MCP tool call) is still open on the stream: that refusal is returned directly, and if the `fallback-credit-2026-07-01` header is set it still carries a credit token redeemable by continuing the partial response. Non-streaming requests are unaffected; the API clears the partial work and retries before responding.
from line 1077
10771077 # Streaming: on a refusal the middleware splices the fallback model's
10781078 # events onto the still-open stream.
10791079 stream = client.beta.messages.stream(
1080 model: "claude-fable-5",
1080 model: Anthropic::Model::CLAUDE_FABLE_5,
10811081 max_tokens: 1024,
10821082 messages: [{role: "user", content: "Hello, Claude"}],
10831083 request_options: {fallback_state: state}
from line 1087
10871087
10881088 # Non-streaming: reusing the state keeps the conversation pinned to the model that accepted.
10891089 message = client.beta.messages.create(
1090 model: "claude-fable-5",
1090 model: Anthropic::Model::CLAUDE_FABLE_5,
10911091 max_tokens: 1024,
10921092 messages: [{role: "user", content: "Hello, Claude"}],
10931093 request_options: {fallback_state: state}
from line 1129
11291129 </Step>
11301130</Steps>
11311131
1132A manual retry writes the fallback model's prompt cache from scratch, which costs more than reading an existing cache. [Fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit) refunds that cost; redeem it on every retry you build yourself. A Claude Haiku 5.5 refusal carries no fallback credit, so a retry after one pays the full cost of writing the fallback model's prompt cache.
1132A manual retry writes the fallback model's prompt cache in full, which costs more than reading an existing cache. [Fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit) refunds that cost; redeem it on every retry you build yourself. A Claude Haiku 5.5 refusal carries no fallback credit, so a retry after one pays the full cost of writing the fallback model's prompt cache.
11331133
11341134## Refusals in Message Batches
11351135
from line 1145
11451145## Common pitfalls
11461146
11471147* **Retry on a different model.** Re-sending a refused request to the same model usually earns another refusal. Point the retry at the fallback model.
1148* **Budget retries per request, not per turn or per session.** A single turn can produce several refusals, for example an agent plus its sub-agents.
1148* **Budget retries for each request, not for each turn or session.** A single turn can produce several refusals, for example an agent plus its subagents.
11491149* **Configure fallback on every request path.** Retry handlers, error-recovery branches, and background workers all need it. A handler that re-issues a request without fallback loses the protection on exactly the requests most likely to need it.
1150* **Give sub-agent calls their own fallback.** The `fallbacks` parameter does not propagate into model calls made from inside tool execution.
1150* **Give subagent calls their own fallback.** The `fallbacks` parameter does not carry over to model calls made from inside tool execution.
11511151* **Make fallback a property of the request, not of ambient state.** A shared flag, cached config value, or global toggle can drift out of sync and silently leave a request unprotected. When you cannot confirm fallback is active, configure it rather than assume it is on.
1152* **Instrument refusals as their own signal.** A refusal is an HTTP 200, so monitoring built on error rates or 5xx responses never sees it. Emit one event per refusal and one per fallback-served response (the `fallback_message` entry in `usage.iterations` marks the latter), then alert on the gap between the two counts.
1152* **Instrument refusals as their own signal.** A refusal is an HTTP 200, so monitoring built on error rates or 5xx responses never sees it. Emit one event for each refusal and one for each fallback-served response (the `fallback_message` entry in `usage.iterations` marks the latter), then alert on the gap between the two counts.
11531153* **Branch on `stop_reason` or `stop_details.type`, not on `content` or the inner `stop_details` fields.** The `stop_details` object is always present on a refusal, but its `category` and `explanation` fields can be `null`. Check for `stop_reason` equal to `"refusal"` directly.
11541154
11551155## Next steps
No line in this hunk matches that.