[BUG] bio safeguard false positive: a public science-news URL is blocked at WebFetch before the page is ever retrieved

Status Open
Reported on v2.1.219
Maintainer reply None cached
Activity 1 comment · opened Aug 5, 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?

I pasted a public phys.org news link as the first and only content of a fresh session. The biology safeguard fired on the WebFetch tool call, before the page had been retrieved, so no page content was involved in the decision. The input was a bare URL and nothing else.

The article is a write-up of a Nature Communications paper about an alpine flower that turns out to be carnivorous. The apparent trigger is ordinary botany vocabulary, words like carnivorous, digest, absorb, prey and enzyme.

Three refusals fired over the life of the session, all categorized bio, all fallbacks to Opus 5 rather than hard blocks. Only the first one was about the plant. Once the article text was in the session, later turns that had nothing to do with biology kept re-triggering it.

What Should Happen?

A link to a mainstream science publication should not be flagged as a biology risk before the content behind it has been retrieved and evaluated. Nothing in this session came close to biological uplift. The subject was a flower.

Failing that, a flag on one tool call should not persist for the rest of the session against unrelated turns.

Error Messages/Logs

Client banner, verbatim:

Fable 5's safeguards flagged this message The safeguards are intentionally broad right now and may flag safe and routine coding, cybersecurity, or biology work. These measures let us bring you Mythos-level capabilities sooner, and we're working to refine them. Switched to Opus 5. [Learn more]

Shown alongside Failed to fetch https://phys.org/news/2026-08-sticky-alpine-darwin-year-carnivorous.html, plus a dismissible "Switched to Opus 5" toast with a "Why?" link. The composer's model chip flipped to Opus 5.

The three matching records from the session transcript. These are the raw type: "system" entries with only the non-content keys included, so there is no conversation text here:

{"type":"system","subtype":"model_refusal_fallback","originalModel":"claude-fable-5","fallbackModel":"claude-opus-5","requestId":"req_011CdkEtDEjgKsq524B2TziM","apiRefusalCategory":"bio","apiRefusalExplanation":null,"timestamp":"2026-08-05T20:34:13.942Z"}
{"type":"system","subtype":"model_refusal_fallback","originalModel":"claude-fable-5","fallbackModel":"claude-opus-5","requestId":"req_011CdkEw2knVQxvxEJJ3rVhG","apiRefusalCategory":"bio","apiRefusalExplanation":null,"timestamp":"2026-08-05T20:35:04.423Z"}
{"type":"system","subtype":"model_refusal_fallback","originalModel":"claude-fable-5","fallbackModel":"claude-opus-5","requestId":"req_011CdkF8AbNufBKvNxvdTf4N","apiRefusalCategory":"bio","apiRefusalExplanation":null,"timestamp":"2026-08-05T20:38:01.817Z"}
The first record, req_011CdkEtDEjgKsq524B2TziM at 20:34:13Z, is the WebFetch call on the URL below. That is the one worth triaging.

Steps to Reproduce

Start a new session with the model set to claude-fable-5.
Send this URL, with no other text, as the first message: https://phys.org/news/2026-08-sticky-alpine-darwin-year-carnivorous.html
Claude attempts WebFetch on that URL.
The request is flagged, the banner above appears, and the turn is served by Opus 5 instead.
The URL was the first message in the session. There was no prior conversation, no accumulated history, no files read, no tool output, nothing else in the transcript that could be blamed for the classification.

Claude Model

Other

Is this a regression?

I don't know

Last Working Version

N/A

Claude Code Version

2.1.219

Platform

Other

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Other

Additional Information

The block did not prevent access to the content. About sixty seconds after the refusal, the same URL was retrieved successfully in the same session using a local headless browser through a shell command. HTTP 200, full article text, no block. The check gates the WebFetch path and does not gate a Bash call to a local browser, so nothing was actually kept out of the context. It cost a round trip and a model downgrade and the content arrived anyway. I am reporting that as an efficacy observation, not as a request that it be made stricter. It is a public news article about a plant and there was nothing here to protect.

A flagged page appears to poison the rest of the session. Refusals two and three fired on turns that had nothing to do with botany. One of them was researching an unrelated question entirely. Once the article text was in context, every turn carrying it forward re-tripped bio, three for three. If that is working as intended it would be useful to say so, because from the user side it looks like one bad classification spreading.

The model toggle does not restore a flagged session. Running /model claude-fable-5 after the block did not bring Fable back. Every turn afterward continued to be served by Opus 5, more than thirty of them. I tried the toggle twice with the same result. If a flagged session cannot be recovered by reselecting the model, then the composer showing "Fable 5" while Opus serves every turn is misleading. Either the toggle should work, or the client should say the session is pinned and offer to start a fresh one.

Wider pattern. This is not a one-off on this account. Across roughly 25 sessions I have close to 100 recorded refusal events. That figure is my own local tally rather than an audited count, but the shape is clear. The large majority are categorized cyber rather than bio, and the large majority are fallbacks rather than hard blocks. Before today, bio had fired exactly twice, and the more recent of those two was a question about caffeine.

I am deliberately keeping the details in this report to the single session above. It is the cleanest example, and my other transcripts contain personal material I am not going to attach to a public issue. I have per-event records with request IDs for the rest if that would help triage, and I am happy to send those privately.

What would help.

A false-positive reporting path in the client, offered at the moment of the block, that captures the request ID automatically. Issue #64287 already proposes this. Reconstructing the three IDs above meant reading them out of the session transcript by hand.
The refusal record surfaced in a form the assistant can see. Right now the block appears in my client but never enters the model's context, so Claude cannot tell it was blocked, cannot explain what happened, and will misdiagnose the resulting truncated output as some other kind of failure.
Some weighting against flagging a bare URL to a mainstream science publication before the content behind it has been retrieved.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗