Workflow fan-out inherits a premium-tier default with no per-agent cost ceiling, causing ~$1k in auto-purchased charges

Open 💬 7 comments Opened Jun 13, 2026 by joshduffy
EDIT 2026-06-13 (correction, see comments): The original "malformed model ID / ANSI escape leak" root cause below is wrong. A byte-level check of the affected settings.json shows zero ESC (0x1b) bytes; [1m] is the legitimate context-tier suffix, not a leaked escape. The model family is decided by the prefix before [1m], so opus[1m] could never resolve to Fable 5. The persisted default was claude-fable-5[1m] (already the fable-5 family), and the runtime ran exactly that. The real, preventable cause is a premium-tier default inherited by a 700+ agent Workflow fan-out with no per-agent model ceiling and no spend gate, with auto-purchase firing without ever surfacing the tier-times-fan-out cost. Billing figures are also corrected in the comments (three card charges totaling $800 usage / $864 with tax, not two). Invoice IDs removed; they live in the support ticket. Original text left intact below for thread continuity.

---

Bug report and billing impact

This is a companion to #68279 (the /model picker bug report). Filing separately because the billing impact warrants its own tracking.

The bug

The /model picker writes a malformed model ID to ~/.claude/settings.json. Instead of a clean ID like claude-opus-4-8[1m], it persists opus[1m] where [1m] is a raw ANSI SGR bold escape sequence leaking from terminal rendering into the serialized JSON value.

  • Deterministic and reproducible (triggered 3x consecutively on 2026-06-13, v2.1.177)
  • The picker reports success even when it writes a corrupt value
  • No settings validation catches the bad ID
  • The bad ID silently resolves to a different (premium) model tier at runtime

Financial impact

On 2026-06-11, the corrupted setting (claude-fable-5[1m]) caused a Workflow to spawn 700+ subagents on Fable 5 (the most expensive tier, $10/$50 per MTok) instead of the intended Sonnet ($3/$15). In under 2 hours:

  • ~$350 in pre-purchased usage credits consumed
  • $200 auto-purchased and charged to card
  • $400 auto-purchased and charged to card
  • A third $200 auto-purchase the following day (corrected total: $800 usage, $864 with tax across three charges)
  • Included Max plan allocation for the billing window consumed (75% of $1,100 limit from one day)
  • Total bug-driven excess: ~$1k (receipted card floor $864; true token burn higher, in the usage console)

The spend limit was hit 3 times, which also corrupted the workflow results (partial verdicts, false "dry round" signals from killed agents).

Root cause chain

  1. /model picker writes malformed ID to settings.json (ANSI escape leak)
  2. Malformed ID silently resolves to Fable 5 (premium tier) at runtime
  3. Workflow subagents inherit the default model from settings.json
  4. 700+ agents run on Fable 5 instead of the intended cheaper model
  5. Spend limit hit repeatedly, auto-triggering prepaid credit purchases
  6. User has no visibility into the corrupted setting until manually inspecting the JSON file

Evidence

  • GitHub issue #68279 (the reproduction)
  • Auto-purchase receipts (in the open support ticket)
  • Git commit b37c6a8 in claude-config repo documenting the fix
  • Session handoffs documenting the incident contemporaneously
  • Post-incident rule file (ultracode-model-routing.md) documenting root cause

Environment

  • Claude Code 2.1.177
  • macOS 15.2 (Darwin 25.5.0)
  • Shell: zsh
  • Max plan (20x)

What should happen

  1. The /model picker should not leak ANSI escape sequences into persisted JSON
  2. Settings validation should reject malformed model IDs on write
  3. At runtime, an unrecognized model ID should error rather than silently resolving to a premium tier
  4. The spend-limit mechanism should not auto-purchase credits without explicit user consent when the overage is caused by a system-side defect

View original on GitHub ↗

This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗