Bare model aliases (sonnet/opus/haiku/fable) fail to resolve through modelOverrides in subagent frontmatter and --model

Status Open
Reported on v2.1.220
Maintainer reply ✓ Yes — bcherny
Activity 3 comments · opened Jul 28, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Description

When availableModels and modelOverrides are both configured in settings.json (common for Bedrock/enterprise setups that map canonical model names to provider-specific inference profile IDs), bare model aliases (sonnet, opus, haiku, fable) fail validation when used in subagent frontmatter (model: sonnet in a .claude/agents/*.md file) or as --model sonnet on the CLI. Instead of resolving through modelOverrides like the full canonical name does, the alias silently falls back to the parent/default model with a warning, or is rejected outright depending on the code path.

Environment

  • Claude Code version: 2.1.220
  • Provider: Amazon Bedrock (CLAUDE_CODE_USE_BEDROCK=1)

Minimal repro settings.json

{
  "availableModels": [
    "claude-opus-5",
    "claude-sonnet-5",
    "claude-fable-5",
    "claude-haiku-4-5"
  ],
  "enforceAvailableModels": false,
  "modelOverrides": {
    "claude-opus-5": "global.anthropic.claude-opus-5[1m]",
    "claude-sonnet-5": "global.anthropic.claude-sonnet-5[1m]",
    "claude-fable-5": "global.anthropic.claude-fable-5[1m]",
    "claude-haiku-4-5": "global.anthropic.claude-haiku-4-5-20251001-v1:0"
  }
}

Repro steps

  1. Apply the settings above (via ~/.claude/settings.json or --settings).
  2. Create a subagent with bare-alias frontmatter:
---
name: test-sonnet-agent
description: test agent pinned to sonnet
model: sonnet
---
You are a test agent. When invoked, just say hi.
  1. Start a session on a different model family, e.g. claude --model opus, then invoke the subagent (e.g. via the Agent/Task tool).
  2. Check debug logs (--debug-file).

Observed behavior

[WARN] Subagent model "sonnet" is not in the availableModels allowlist; inheriting the parent model instead
...
dispatching to bedrock model=global.anthropic.claude-opus-5[1m]

The subagent runs on Opus instead of Sonnet, silently ignoring the frontmatter model: sonnet directive. This reproduces consistently across several availableModels/modelOverrides variations, including ones that list the raw Bedrock inference-profile strings directly.

Separately, claude --model sonnet -p "..." (headless CLI flag, same settings) also silently falls back to Opus 5 with no warning at all — worse than the subagent case, which at least logs a WARN.

By contrast, the interactive /model command surfaces an explicit error for the same alias:

Model 'sonnet' is not available. Your organization restricts model selection.

Expected behavior

Using the full canonical name works correctly in all cases:

model: claude-sonnet-5
dispatching to bedrock model=claude-sonnet-5

The bare alias should resolve through modelOverrides the same way the full name does — i.e., alias resolution should happen before (or account for) the modelOverrides mapping and the resulting provider-native model ID (e.g. global.anthropic.claude-sonnet-5[1m]) should be checked for membership via the reverse override mapping, not a literal startsWith match against the availableModels allowlist entries.

Impact

Any org using Bedrock/Vertex/Foundry with modelOverrides (needed to map canonical Claude names to provider-specific inference profile ARNs/IDs) cannot reliably use short model aliases in subagent frontmatter or --model — they must always spell out full canonical names. This is easy to trip over silently, since two of the three failure modes produce no visible error (silent fallback to a different, possibly more expensive model) and only one produces an explicit rejection.

View original on GitHub ↗

3 Comments

tomoki241 · 2 months ago

Apologies if I have misunderstood any of the implementation details. I do not usually comment on GitHub issues.

I came across this issue after noticing unexpected behavior on Amazon Bedrock when using availableModels, modelOverrides, and /model. I searched through a number of existing issues to see whether others had encountered similar behavior, which eventually led me here.

After reading the current Model configuration documentation, most of the per-surface behavior in this report appears to match what the documentation describes. One unresolved exception is --model: the documentation says that substitution occurs with a warning naming both the requested and substituted models, while this report says that the substitution is silent.

My broader interest is cross-provider consistency. I use Claude Code through a personal Claude subscription for research, but Amazon Bedrock in my work environment. Being able to reuse the same agent definitions and model-selection settings with equivalent behavior would make it much easier to transfer workflows between those environments.

I understand that this may be a feature request rather than a bug under the current documentation. Still, I hope the team will consider bringing Bedrock and other provider-specific deployments closer to the alias-resolution behavior available with Anthropic-hosted usage. The related issues below may be different manifestations of the same boundary between Claude's canonical model identity and provider-specific deployment IDs.

Separately, the missing --model warning appears to be a narrower, independently actionable issue. One detail would help confirm it: was stderr captured in the non-interactive reproduction?

claude --model sonnet -p "..." --output-format text \
  >stdout.txt 2>stderr.txt

If stderr.txt is empty, the missing warning appears to be a clear documentation-versus-implementation mismatch. If the warning is present there, the broader portability question remains.

---

<details>
<summary>Detailed comparison with the current documentation, cross-provider implications, and possibly related issues</summary>

Documented per-surface behavior

Restrict model selection says that on Amazon Bedrock and other providers using provider-specific deployment IDs, a blocked family alias follows the rejection or replacement path rather than resolving to the newest permitted version of its family. The alias-to-newest-permitted-version behavior introduced in v2.1.205 is documented for the Anthropic API and Claude Platform on AWS, not Amazon Bedrock.

Blocked aliases then follow per-surface rules:

| Where specified | Documented behavior | This report |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| /model | Rejected with an error | Matches |
| --model, ANTHROPIC_MODEL, or the model setting | Replaced at startup with a warning naming both the requested and substituted models | Replacement matches; whether the warning was emitted to stderr is not yet clear |
| Subagent, skill, or command frontmatter | Falls back to the inherited or default model | The reported subagent behavior matches, with a warning in the debug log |

The surface-specific outcomes themselves therefore appear to be documented. They may not represent three separate defects.

Yet the distinction has a concrete consequence: a configuration that is portable in form is not necessarily portable in behavior.

Cross-provider consistency

From a user's perspective, the desired invariant seems simple: when an organization permits a Sonnet model, model: sonnet should select an allowed Sonnet model in both Anthropic-hosted and Bedrock environments. The organization should still control the permitted version, and modelOverrides should still control the provider-native ID ultimately sent to Bedrock.

Today, the same family alias can resolve normally in one environment but be rejected or replaced in another. In subagent frontmatter, that replacement may silently change the model family by inheriting the parent model. This makes agent definitions developed in one environment less reliable when transferred to another, even when both environments are intended to expose the same Claude model families.

The warning behavior matters, but a warning alone would not restore that portability.

The --model warning may be independently actionable

The documentation says that an excluded startup selection is replaced with a warning naming both the requested and substituted models. This report says that claude --model sonnet -p "..." falls back to Opus 5 without any visible warning.

That is a consequential failure mode: the session can run on a different, possibly more expensive model without making the substitution visible to the caller.

The documentation separately notes that model-remapping warnings are written to stderr in non-interactive mode when the default text output format is used. Those warnings are suppressed with --output-format json or stream-json.

I could not determine from the documentation alone whether an allowlist-substitution warning uses the same stderr path. If the warning appears in stderr.txt, the behavior may be consistent with the documentation even though it is easy to miss. If stderr is also empty, the missing warning stands as a narrow implementation-versus-documentation mismatch regardless of how the broader alias-resolution question is resolved.

availableModels and modelOverrides

The reproduction lists full model IDs such as claude-sonnet-5 while selecting the family alias sonnet.

The modelOverrides section says that allowlist matching is performed against the Anthropic model ID rather than the provider-specific override value. It also says that overrides apply when an Anthropic model ID is supplied directly through model-selection settings.

That makes the boundary between a full model ID and a family alias worth isolating.

Testing family entries may help:

{
  "availableModels": [
    "sonnet",
    "opus",
    "haiku",
    "fable"
  ]
}

This gives up strict version pinning, so it is not necessarily a suitable production configuration. As a diagnostic comparison, however, it may show whether the alias is being rejected during allowlist matching before modelOverrides can apply.

If this is tested, the debug log should also be checked to confirm which provider-native model ID was actually dispatched. Successful startup alone would show only that the alias passed the allowlist, not that it reached the intended Bedrock inference profile.

Possible framing

This appears to contain two related concerns:

  1. Cross-provider consistency: extend alias-to-permitted-version resolution to Amazon Bedrock and other providers that use deployment-specific model IDs, so the same agent and model configuration retains equivalent semantics across environments.
  2. Possible warning bug: --model <alias> is substituted without the documented warning, if stderr is also empty when using the text output format.

The second concern may be independently actionable, but resolving it would not address the broader portability problem.

Possibly related:

  • #37894 — /model drops the Sonnet 1M entry when availableModels and modelOverrides are combined; closed as not planned and currently labeled stale
  • #10169 — Bedrock inference profile ARNs configured through ANTHROPIC_DEFAULT_*_MODEL can be selected through /model <alias> but do not appear in the /model picker; currently open
  • #27890 — Bedrock application inference profile ARNs are not mapped back to Claude's internal model identities, affecting model-dependent behavior; closed as not planned and currently labeled stale

I am reading the documentation rather than the implementation, so I may be missing constraints imposed by provider-specific deployment IDs. Even so, the user-facing portability gap remains. If the stderr capture is also empty, the missing --model warning stands on its own.

</details>

---

English is not my first language, and while I can read it reasonably well, I am not very experienced in writing technical comments in English. I researched this as carefully as I could and used AI to help organize and express my findings, so I apologize if any part comes across as AI-generated noise, is unnecessarily verbose, or misses the point.

Thank you to the Claude team and the community for all the work that makes this project possible.

bcherny collaborator · 1 month ago

Thanks for the precise writeup — reproduced on the current release (2.1.233, Linux) using your exact settings.json:

  • claude --model sonnet -p ... silently runs on the default model (Opus, via its override) with no warning at all — confirmed via debug logs showing the request dispatched to the Opus inference profile.
  • claude --model claude-sonnet-5 -p ... correctly targets Sonnet, as you found.
  • Interactive /model sonnet shows the explicit "Model 'sonnet' is not available. Your organization restricts model selection." error.

So the core problem stands: with an availableModels allowlist of canonical names plus modelOverrides, bare family aliases fail the allowlist check even though the family they resolve to is clearly permitted — and the headless --model path does this silently, which is the most dangerous of the three behaviors. Marking as a confirmed bug.

One partial improvement to note: since 2.1.222 (after the 2.1.220 you tested), subagent/teammate frontmatter family aliases that fail the allowlist now step down to the newest org-allowed model in that family instead of inheriting the parent model, which should mitigate the model: sonnet frontmatter case specifically. The --model flag and alias-resolution inconsistency remain, as does the silent (no-warning) fallback. Until it's fixed, spelling out full canonical names is the reliable workaround, as you noted.

🤖 Generated with Claude Code

marcindulak · 19 days ago

For your information: the label reproduced on this issue does not prevent it from becoming stale and eventually auto-closed. See https://github.com/anthropics/claude-code/issues/87647 for details, and consider upvoting that for visibility.