[BUG] Desktop + Bedrock: Haiku 4.5 sent as bare model ID (not inference profile) on Scheduled Task follow-ups → intermittent 400 "invalid model identifier"
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?
In Claude for Desktop (Local Agent Mode / Cowork) configured for AWS Bedrock, typing a
follow-up message into a Scheduled Tasks session fails with:
API Error (claude-haiku-4-5-20251001): 400 The provided model identifier is invalid.
The app applies the model to the session via LocalAgentModeSessions.setModel using the bare
model ID claude-haiku-4-5-20251001 instead of the configured Bedrock inference-profile IDglobal.anthropic.claude-haiku-4-5-20251001-v1:0. Bedrock rejects the bare ID because in this
account/region Haiku 4.5 is only invokable via an inference profile.
The failures alternate every other follow-up, and the logs show exactly why:
- A Haiku follow-up sets the bare ID, then sends → 400.
- Immediately after the failure, the app re-sets the qualified profile ID on the session.
- The next follow-up therefore runs with the qualified ID → succeeds.
- The follow-up after that re-applies the bare ID → 400 again.
This bare↔qualified toggle on each follow-up produces the observed ~50% failure rate.
The bug is specific to Haiku. The exact same follow-up path sends the correctly-qualified profile
ID for Sonnet (global.anthropic.claude-sonnet-4-6) on every turn, and those turns always succeed.
It occurs only when all of these hold:
- In the Scheduled Tasks tab (not in normal conversations)
- Model is Haiku (Sonnet / Opus are unaffected)
- The request is a user follow-up after the scheduled task ran — the scheduled task's own turns
succeed, even across multiple turns
Independent Bedrock confirmation (same role/account/region the app uses):
get-inference-profile global.anthropic.claude-haiku-4-5-20251001-v1:0→status: ACTIVEconverse --model-id global.anthropic.claude-haiku-4-5-20251001-v1:0→ 10/10 OKconverse --model-id us.anthropic.claude-haiku-4-5-20251001-v1:0→ OKconverse --model-id claude-haiku-4-5-20251001(the bare ID) →
ValidationException: The provided model identifier is invalid. — matches the app error exactly
So the model is enabled and the profile works; only the bare ID is rejected. The defect is the app
applying the unqualified identifier on this code path for Haiku.
What Should Happen?
On the interactive follow-up / setModel path, when the inference provider is Bedrock, the app
should apply the fully-qualified inference-profile ID
(global.anthropic.claude-haiku-4-5-20251001-v1:0) — exactly as the scheduled-task run path and the
Sonnet path already do — rather than the bare claude-haiku-4-5-20251001. Every Haiku follow-up
should succeed, with no alternating 400s.
Error Messages/Logs
Chronological chain from `~/Library/Logs/Claude-3p/*.log`, single session (IDs redacted as
`XXXX`). Note how `setModel` toggles between the bare and qualified ID, and each turn's outcome
follows the ID that was active when it was sent:
# --- Scheduled task runs: model built from configured list = QUALIFIED -> healthy ---
[CycleHealth] Healthy cycle: { ... model: 'global.anthropic.claude-haiku-4-5-20251001-v1:0', cycle_health: 'healthy' }
# --- Follow-up #1: app sets the BARE id, then sends -> 400 ---
LocalAgentModeSessions.setModel: sessionId=XXXX, model=claude-haiku-4-5-20251001
LocalAgentModeSessions.sendMessage: sessionId=XXXX, ...
[APIError] Intermediate SDK error "model_not_found" for session XXXX — continuing to read stream
[Result] Turn failed for session XXXX: subtype=success, is_error=true
[CycleHealth] Unhealthy cycle: {
... model: 'claude-haiku-4-5-20251001', cycle_health: 'unhealthy', unhealthy_reason: 'api_error',
error_message: 'API Error (claude-haiku-4-5-20251001): 400 The provided model identifier is invalid..' }
# --- App re-sets the QUALIFIED id right after the failure ---
LocalAgentModeSessions.setModel: sessionId=XXXX, model=global.anthropic.claude-haiku-4-5-20251001-v1:0
# --- Follow-up #2: inherits the QUALIFIED id -> healthy ---
LocalAgentModeSessions.sendMessage: sessionId=XXXX, ...
[CycleHealth] Healthy cycle: { ... model: 'global.anthropic.claude-haiku-4-5-20251001-v1:0', cycle_health: 'healthy' }
# --- Follow-up #3: app sets the BARE id again -> 400 (same as #1) ---
LocalAgentModeSessions.setModel: sessionId=XXXX, model=claude-haiku-4-5-20251001
[CycleHealth] Unhealthy cycle: {
... model: 'claude-haiku-4-5-20251001', unhealthy_reason: 'api_error',
error_message: 'API Error (claude-haiku-4-5-20251001): 400 The provided model identifier is invalid..' }
LocalAgentModeSessions.setModel: sessionId=XXXX, model=global.anthropic.claude-haiku-4-5-20251001-v1:0 # re-set qualified again
# --- Switch to Sonnet: follow-up path uses the QUALIFIED id, every turn -> healthy ---
LocalAgentModeSessions.setModel: sessionId=XXXX, model=global.anthropic.claude-sonnet-4-6
[CycleHealth] Healthy cycle: { ... model: 'global.anthropic.claude-sonnet-4-6', cycle_health: 'healthy' }
LocalAgentModeSessions.sendMessage: sessionId=XXXX, ...
[CycleHealth] Healthy cycle: { ... model: 'global.anthropic.claude-sonnet-4-6', cycle_health: 'healthy' }
Per-turn summary of the same session (the `setModel` value is what was active when each turn was
sent; the post-failure re-set to the qualified ID is what lets the *next* turn succeed):
| Turn | Trigger | `setModel` (active when sent) | `CycleHealth.model` | Result |
|------|---------|-------------------------------|---------------------|--------|
| Scheduled run | task | `global.…haiku…-v1:0` (from config) | `global.…haiku…-v1:0` | ✅ healthy |
| Follow-up #1 | user | `claude-haiku-4-5-20251001` (bare) | `claude-haiku-4-5-20251001` | ❌ 400 |
| Follow-up #2 | user | `global.…haiku…-v1:0` (re-set after #1) | `global.…haiku…-v1:0` | ✅ healthy |
| Follow-up #3 | user | `claude-haiku-4-5-20251001` (bare) | `claude-haiku-4-5-20251001` | ❌ 400 |
| Follow-up #4 | user | `global.…haiku…-v1:0` (re-set after #3) | `global.…haiku…-v1:0` | ✅ healthy |
| Switch to Sonnet | user | `global.anthropic.claude-sonnet-4-6` | `global.anthropic.claude-sonnet-4-6` | ✅ healthy |
| Sonnet follow-up | user | `global.anthropic.claude-sonnet-4-6` (retained) | `global.anthropic.claude-sonnet-4-6` | ✅ healthy |
Steps to Reproduce
Prerequisites: Claude for Desktop configured for AWS Bedrock, in a region where Haiku 4.5 requires an
inference profile (e.g. us-west-2), with the model list specifying the qualified profile IDs:global.anthropic.claude-haiku-4-5-20251001-v1:0, global.anthropic.claude-sonnet-4-6,global.anthropic.claude-opus-4-6-v1.
- Create a Scheduled Task and set its model to Haiku 4.5.
- Let the scheduled task run (it succeeds, even over multiple turns).
- In that scheduled-task session, send a follow-up message → it fails with
API Error (claude-haiku-4-5-20251001): 400 The provided model identifier is invalid.
- Send another follow-up → it succeeds.
- Send another follow-up → it fails again. (Failures alternate every other follow-up.)
- In the same session, switch the model to Sonnet and send follow-ups → all succeed.
- Inspect
~/Library/Logs/Claude-3p/main.log: failing turns are preceded by
setModel ... model=claude-haiku-4-5-20251001 (bare); after each failure the app re-sets
setModel ... model=global.anthropic.claude-haiku-4-5-20251001-v1:0, which is why the next turn
succeeds. Sonnet turns always use the qualified global.anthropic.… ID.
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
n/a
Claude Code Version
Claude for Desktop 1.10628.0 (bundled claude-code SDK 2.1.160)
Platform
AWS Bedrock
Operating System
macOS
Terminal/Shell
Other
Additional Information
Possible Root cause: On the interactive follow-up path in Local Agent Mode, setModel applies the bare
Haiku ID claude-haiku-4-5-20251001 to the session instead of the configured Bedrock
inference-profile ID global.anthropic.claude-haiku-4-5-20251001-v1:0, so the turn 400s. After the
failure the app re-sets the qualified ID on the session — so the next follow-up succeeds, then the
following follow-up re-applies the bare ID and fails again. This bare↔qualified toggle is what
produces the alternating fail/succeed (50%) pattern. Sonnet/Opus are applied with the qualified ID
on every turn, which is why the bug is Haiku-specific. The scheduled task's own turns build the model
from the configured model list and are unaffected.
Suggested fix: On the setModel / interactive follow-up code path, when the provider is Bedrock,
apply the fully-qualified inference-profile ID from the configured model list (as the scheduled-run paths already do) rather than a stripped/bare model name — and don't toggle back to the bare ID on subsequent follow-ups.
Workarounds:
- Switch the scheduled-task follow-up conversation to Sonnet (and optionally back to Haiku).
- For Haiku, the every-other-turn failure can be worked around by resending, but the scheduled task
itself runs fine regardless.
Notes:
- The managed/configured model list is correct (qualified
global.profile IDs); no user config
overrides the model. The bare ID is applied by the app, not read from any config.
- Sensitive identifiers (AWS account ID, SSO details, session IDs, tokens) have been redacted as
XXXX.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗