[Bug] Subagent Task launches with claude-fable-5 resolved model served as claude-opus-5

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

Bug Description

# Bug report: subagent requests resolved to claude-fable-5 are served by claude-opus-5 (~94% of launches) Environment: Claude Code 2.1.221, macOS, Anthropic API (first-party). Subagents via the Task tool. No fallbacks opt-in, no custom base URL, no proxy. Expected: a Task subagent launch whose harness-resolved model is claude-fable-5 (recorded in the parent transcript's toolUseResult.resolvedModel at async_launched) is served by claude-fable-5. Actual: the child transcript's per-turn API response field (message.model on assistant rows, isSidechain:true) reads claude-opus-5 for ~94% of such launches — uniformly from the first API call of the run (no mid-run switch, no fallback notice in any transcript, stop_reason: "refusal" never involved). Incidence (one multi-day session file, 134 subagent runs; extraction = grep -o '"model":"…"' | sort | uniq -c over parent + child JSONLs): | resolvedModel (launch intent) | n launches | served as requested | served claude-opus-5 | |---|---|---|---| | claude-fable-5 | 52 | 3 | ~49 | | claude-opus-4-8[1m] | 57 | 57 | 0 | | claude-sonnet-5 | 14 | 14 | 0 | | claude-haiku-4-5-20251001 | 2 | 2 | 0 | | claude-opus-5[1m] (explicit) | 5 | 5 | — | - Only fable-5 requests are affected; every other id is served faithfully. - The substitution is subagent-specific: the MAIN conversation of the same session, also fable-5, was served claude-fable-5 on all 2,202 assistant rows. - Both outcomes occur in the same minute: two launches in one tool-call block — one served opus-5, the sibling served fable-5. - Affected runs include launches where fable-5 was resolved from CLAUDE_CODE_SUBAGENT_MODEL=claude-fable-5 (env), and (in one case) where a model:"haiku" per-call arg was correctly overridden by that env var to fable-5 — then served opus-5. - Children mis-self-identify (they claim fable when served opus-5), so only the transcript message.model field exposes this; the launch-time resolvedModel (which the UI header appears to display) shows the requested fable-5, masking the swap. Impact: (1) cost — opus-5 serving billed against fable-5 requests (~49 full agent runs here, hundreds of thousands of tokens); (2) policy — model-governance rules keyed to "which model runs" are silently bypassed (in our case a then-active opus-5 exclusion was violated by runs the config had resolved to fable-5); (3) any evaluation attributing subagent behavior to fable-5 is contaminated. Ruled out: documented safety-classifier fallback (requires a transcript notice + a refusal; zero notices across all transcripts, substitution present from row 1); fallbacks parameter (not opted in, and it only re-runs refusals); alias mis-resolution (the harness resolution layer is correct in every record — the divergence is between the resolved request and the serving response). Repro: launch Task subagents with subagent model = claude-fable-5 (env var or default) and compare toolUseResult.resolvedModel in the parent JSONL against message.model in ~/.claude/projects/<slug>/<session>/subagents/agent-<id>.jsonl. In our session the mismatch appears in ~16 of every 17 fable-5 launches.

Environment Info

  • Platform: darwin
  • Terminal: iTerm.app
  • Version: 2.1.221
  • Feedback ID: 287768e4-3c7e-428b-82df-e236d80a9fa9

Errors

[]

View original on GitHub ↗