[BUG] Safeguard refusal cites the AUP and drops the API's own explanation, which cites a different policy ("duplicating model outputs")

Status Open
Reported on v2.1.246
Maintainer reply None cached
Activity 0 comments · opened Aug 27, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When the safeguards block a turn, the message Claude Code shows attributes the block to the Acceptable Use Policy and gives an opaque classifier tag. The API response's own explanation — which Claude Code receives and writes to the session transcript — attributes it to a different policy, and is never shown to the user.

Two distinct presentation defects, both independent of whether the classifier was correct:

1. The policy attribution is wrong. The UI links the AUP (https://www.anthropic.com/legal/aup). The API cites the commercial terms' restriction on "reverse engineering or duplicating model outputs" (https://www.anthropic.com/legal/commercial-terms). Those are different documents making different claims. A user who reads the UI concludes they wrote something abusive; the actual accusation is that they were extracting model outputs. Neither Details: [reasoning_extraction] nor the AUP link conveys that.

2. apiRefusalExplanation is silently dropped. The client is handed a human-readable sentence explaining the block and displays a bracketed tag instead. Nothing in the UI hints that a fuller explanation exists, let alone that it is sitting in the transcript on disk.

Scope: I am deliberately not asking this issue to adjudicate the classifier. I believe my block was a false positive, but that is reported extensively already (#87640, #88448, #89503, #88526, #83245, #75668 and many more). This issue is only about the client showing a different policy from the one the API named, and discarding the explanation it was given.

Why it matters: [reasoning_extraction] is close to unreadable as a user-facing string, and the inference a user draws from the AUP link is the wrong one. The API's sentence at least names a claim they can recognise as mistaken and report accurately — relevant when the blocked message was the single word reconcile. I suspect this is part of why the false-positive reports in this repo are so consistently bewildered.

It also degrades the reports themselves. Nearly every issue in this family quotes the generic UI string; almost none quote apiRefusalExplanation, because you only find it by reading the JSONL. Triage is losing the most specific field in the record.

What Should Happen?

  1. Render apiRefusalExplanation in the error block whenever the API supplies it.
  2. Link the policy the API actually cited (here https://www.anthropic.com/legal/commercial-terms), or link nothing at all, rather than defaulting to the AUP.
  3. Keep Details: and the Request ID exactly as they are — those parts are useful.

Error Messages/Logs

# What the user was shown:

API Error: Opus 5's safeguards flagged this message (https://www.anthropic.com/legal/aup).
This sometimes happens with safe, normal conversations. Claude Code can't respond to this
message with Opus 5.

Try rephrasing the request in a new session or change your model.

Learn more: https://support.claude.com/en/articles/16049681

Details: `[reasoning_extraction]`

Request ID: req_011CeTsnMNRkSAVW1eaxDDpJ


# What the API actually said, from the SAME turn, in
# ~/.claude/projects/<project>/<session>.jsonl :

{
  "type": "system",
  "subtype": "model_refusal_no_fallback",
  "originalModel": "claude-opus-5",
  "requestId": "req_011CeTsnMNRkSAVW1eaxDDpJ",
  "apiRefusalCategory": "reasoning_extraction",
  "apiRefusalExplanation": "This request was blocked as it seems to violate Anthropic's Terms of Service restrictions on reverse engineering or duplicating model outputs. To learn more, visit https://www.anthropic.com/legal/commercial-terms.",
  "version": "2.1.246"
}

# The same string also appears on the assistant record for the turn, at
# message.stop_details.explanation

Steps to Reproduce

The refusal itself is not reproducible on demand — that is true of everything in this family. The presentation defect is durably recorded and trivially checkable on any past occurrence:

  1. Find a session that was blocked by the safeguards:

``
grep -l model_refusal_no_fallback ~/.claude/projects/*/*.jsonl
`
(On this machine that matches 4 sessions.
model_refusal_fallback` also matches.)

  1. Pull the refusal record:

``
grep -h apiRefusalExplanation ~/.claude/projects/*/*.jsonl | python3 -m json.tool
``

  1. Compare apiRefusalExplanation against what was displayed in the UI for that same

requestId (the API Error: text is stored on the adjacent assistant record).

  1. Observe: the transcript names the commercial terms and gives a full sentence; the UI named

the AUP and gave only Details: [reasoning_extraction].

To see it live, any safeguard false positive will do — the mismatch is in how the client renders a refusal, not in what triggered it.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.246 (Claude Desktop app; note claude --version on this machine reports a stale CLI on PATH, not what the app runs)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Context for the block itself (background, not the ask)

  • 8 consecutive blocked turns, 2026-08-27 20:22:31Z – 20:29:52Z, every one

apiRefusalCategory: reasoning_extraction and subtype: model_refusal_no_fallback.

  • 7 in one long session (47,173 transcript lines / 113 MB); 1 in a brand-new session, which

is worth noting because the error text advises "Try rephrasing the request in a new session."
The new session was blocked on its first message. A plain-text message two minutes later
succeeded.

  • The messages blocked, in order: a normal multi-clause work instruction; the same request

shortened; the single word reconcile; you don't like the word reconcile??; a
screenshot of the error with WTF; then further retries. Ordinary configuration/QA work —
no security, biology, or model-internals content anywhere in the session.

  • Request IDs: req_011CeTsnMNRkSAVW1eaxDDpJ, req_011CeTssuPQTmea4CRNKAiBG,

req_011CeTsvHjsaApJSSiPUMvkt, req_011CeTswa6uEVtJaciKjPS46,
req_011CeTsyEcvpV5fgS7c1qX6L, req_011CeTt75s4BuH7rLJpSkWmY.

  • Extended thinking was on, effort high.

Overlap disclosure

The false-positive behaviour overlaps the large reasoning_extraction cluster (#87640, #88448,
#89503, #88526, #88364, #83245, #75668). I have added my data as comments on #87640 and #83245
rather than restating it here. I could find no existing issue about the refusal message's own
content — the wrong policy link and the dropped apiRefusalExplanation — which is why this is
filed separately. Happy for it to be folded into a tracking issue if one exists that I missed.

One incidental observation

The error text appears to have been shortened between versions. #83245 (2.1.220) quotes *"Our
intentionally broad safeguards allow us to deliver more capabilities faster, but can sometimes
flag legitimate coding, cybersecurity, and biology tasks." Mine (2.1.246) reads only "This
sometimes happens with safe, normal conversations."* The longer version was more informative —
it at least named the categories that over-trigger.

View original on GitHub ↗