Subagents silently served a different model than requested when Fable overage consent has not been granted on that machine

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

Summary

Subagents spawned with an explicit model: "fable" were served claude-opus-5 instead. The first API request ran on Fable, every request after it ran on Opus. No error, warning, or record of the substitution was written anywhere, and the subagent was never informed.

This is not capacity fallback. No fallbackModel is configured, the first request of every subagent was served Fable, and the behaviour tracked a config key rather than load. It is also not simply "consent is required": the report is about the substitution being silent and unrecorded, not about the consent gate existing.

The affected machine had never granted Fable overage consent. Granting it stopped the behaviour.

Environment

Claude Code 2.1.220. Ubuntu 24.04 x86_64 and macOS, same subscription account, Claude Max plan, claude.ai OAuth, no API key. Session model opus[1m]. No fallbackModel configured.

What we saw

On a machine whose ~/.claude.json does not contain fableOverageConsentV2, in an interactive session with session model opus[1m], spawn a subagent with model: "fable" set explicitly and give it work that needs more than one API request.

agent-<id>.meta.json records what was requested:

{"agentType":"...","spawnDepth":1,"model":"fable"}

agent-<id>.jsonl records what was actually served:

request #1   claude-fable-5
request #2   claude-opus-5
request #3+  claude-opus-5

Measured across six subagents: every one served Fable on the first API request and Opus on all the rest.

The served model is recorded per assistant message, so the substitution can be found afterwards by comparing meta.json against every record in the .jsonl. What is never recorded is that a substitution happened, or why: no error, no system record, no warning. The only sign at the time was a header in the terminal UI reading Fable 5 -> Opus 5 (1M context), which is not written to the transcript.

The same test on a second machine on the same account passed every time, which made this look host-specific for several hours. It was not. The second machine had granted consent long ago.

How we fixed it

Ran /model in an interactive session on the affected machine and selected Fable 5. The picker noted "Draws from usage credits". ~/.claude.json then contained:

fableOverageConsentV2: {"<org-uuid>": true}

Ran /model again to set the session model back to Opus 5 (1M context), so the retest matched the original conditions. Re-ran the identical test: eight subagents, all requesting fable, session model opus[1m]. Result: 59 assistant turns, 48 tool calls, 100 percent claude-fable-5, zero substitutions.

Six out of six subagents substituted before. Zero out of eight after. No other change to the machine or the test.

What we did not establish

Stated plainly so nobody wastes time on it:

  • We did not isolate the key on its own. The fix was performed through the /model picker, which also writes other session state. We did not hand-add only the key.
  • We did not test the reverse direction. We do not know whether deleting fableOverageConsentV2 from an already-consented machine reproduces the behaviour. Anyone triaging this on a machine that already has the key will likely need to test that first.
  • We cannot explain why the first API request of every subagent was still served Fable if consent was missing. Only the requests after it were substituted. That pattern was consistent across all six.

Why it matters

Agents ran on a model the user did not choose. The subagent is never informed, so it cannot report the substitution or compensate for it. Finding out requires comparing meta.json against every assistant record in the transcript, which nothing does by default.

The substituted model is the session default. Anything that depends on two different models being used, for example one model checking another model's work, silently collapses into one model doing both, and reports success.

The consent state lives in ~/.claude.json, which is not part of any synced configuration. Two machines on the same account with byte-identical settings.json behaved differently, and there was no way to see that difference short of diffing that file.

What should happen instead

It should prompt, or it should fail outright and say why. Silent substitution should not be an option.

If consent cannot be collected from a subagent context, the subagent should fail with a clear reason so the user can grant consent and retry. A failed run that says why is recoverable. A silent substitution is not, because nobody knows it happened.

Separately, and regardless of which consent behaviour is chosen, the substitution should be recorded: a system record in the transcript carrying requested model, served model, and reason. Transcripts already carry system records. agent-<id>.meta.json should also record the served model alongside the requested one.

View original on GitHub ↗