How to handle a Claude Fable 5 refusal with a fallback model
Detect the refusal stop reason and opt into a server-side fallback so a declined request is re-served by another model.
Claude Fable 5 runs safety classifiers that can decline a request. A decline comes back as a successful HTTP 200 with stop_reason set to refusal, not as an exception. If your code reads response.content directly, it will break on these. Worse, false positives can hit benign adjacent work. This guide shows how to detect the refusal and opt into a fallback model so the request is rescued automatically.
- The Anthropic SDK with access to claude-fable-5
- An organization with 30-day data retention (Fable 5 is not available under zero retention)
- A fallback model in mind, typically claude-opus-4-8
Step 1: Check stop_reason before reading content
Always branch on stop_reason first. A pre-output refusal has an empty content array and is not billed. A mid-stream refusal bills the partial output, which you should discard. Reading content[0] without this guard throws on refused requests.
resp = client.messages.create(
model="claude-fable-5",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
)
if resp.stop_reason == "refusal":
print("declined:", resp.stop_details.category if resp.stop_details else None)
else:
print(resp.content[0].text)Step 2: Opt into a server-side fallback
Fallbacks are opt-in. On the beta endpoint, pass the server-side-fallback beta header and a fallbacks list. On a policy decline the API runs the next model on the same request and returns its answer, with credit-style repricing applied automatically. Ship this by default in new Fable 5 code.
resp = client.beta.messages.create(
model="claude-fable-5",
max_tokens=1024,
betas=["server-side-fallback-2026-06-01"],
fallbacks=[{"model": "claude-opus-4-8"}],
messages=[{"role": "user", "content": prompt}],
)
for block in resp.content:
if block.type == "fallback":
print(f"{block.from_.model} declined; {block.to.model} continued")Step 3: Confirm which model served the answer
A fallback block in content marks each switch point. The reliable served-by signal is a fallback_message entry in usage.iterations, which also covers sticky follow-up turns that carry no block. Pair it with stop_reason, since the fallback model can itself refuse.
fallback_ran = any(
entry.type == "fallback_message"
for entry in (resp.usage.iterations or [])
)
if fallback_ran and resp.stop_reason != "refusal":
print("served by", resp.model)Result: a benign security-tooling prompt that Fable 5 declined with a cyber category now returns a real answer. The fallbacks list re-served it on Opus 4.8 inside the same call, the fallback_message entry confirmed Opus produced the response, and the declined Fable attempt cost nothing.
Watch related tutorials
1:42:18
28:14
41:09
9:47
8:23
52:31