Desktop remote-SSH: native model picker sends bare model id, hangs/falls back instead of resolving to org's custom-role slug
Status Open
Reported on v2.1.266
Maintainer reply None cached
Activity 0 comments · opened Sep 14, 2026
Environment
- Claude Desktop (macOS) connected via remote-SSH to a Linux/arm64 devcontainer
- Remote CLI (
ccd-cli, the binary Desktop deploys for SSH sessions): reproduced on 2.1.266, 2.1.268, and 2.1.270 — not version-specific - Org has a custom model-role configuration (
orgModelDefaultCache.data_source: "custom_role_configuration"), exposing models under@anthropic/<model-id>-style slugs (e.g.@anthropic/claude-opus-5) - Requests route through an internal API gateway (custom
ANTHROPIC_BASE_URL+ auth headers) — confirmed not relevant to the bug (see below)
Symptom
Picking "Opus 5" (or Sonnet 5, or Haiku 4.5) from Desktop's native /model picker over a remote-SSH connection shows:
Claude Code notice: Model "claude-opus-5" is restricted by your organization's settings. Using claude-sonnet-5 instead.
...and the session silently runs on the org default model instead of the one selected.
Repro (isolated from Desktop, direct CLI invocation over SSH)
$ ccd-cli -p "say hi" --model claude-opus-5 --output-format json
→ hangs indefinitely (30s+ timeout, no output, no error)
$ ccd-cli -p "say hi" --model "@anthropic/claude-opus-5" --output-format json
→ returns in ~4s, modelUsage: {"@anthropic/claude-opus-5": {...}}
$ ccd-cli -p "say hi" --model opus --output-format json
→ returns in ~4s, resolves internally to "@anthropic/claude-opus-5"
Same pattern reproduces identically for claude-sonnet-5/claude-haiku-4-5-20251001 vs. their @anthropic/-prefixed and alias forms — not model-specific.
What's been ruled out (each tested directly, no effect):
- CLI version skew (reproduced identically on 2.1.266, 2.1.268, 2.1.270)
ANTHROPIC_DEFAULT_OPUS_MODEL/_SONNET_MODEL/_HAIKU_MODELenv vars — these only affect alias resolution (opus→…), not literal bare-id requestsavailableModelsallowlist in managed settings — added the bare ids explicitly, zero change in behavior- Server-side entitlement data is not the issue —
modelAccessCachealready lists the bare id asentitled: true - Not a network/gateway issue — packet capture of the actual outgoing request shows the model field already silently rewritten to the org default (
"model":"claude-sonnet-5") before the request is built, or (more often) no request is ever sent at all (process hangs pre-network)
Root cause (inferred from behavior, not source access)
There appear to be two separate resolution paths for a --model value:
- Fast path for known aliases (
opus/sonnet/haiku) and exact@anthropic/-prefixed custom-role slugs — resolves directly from the already-cachedmodelAccessCache/orgModelDefaultCache. - A different path for a bare canonical id that isn't a recognized alias or exact custom-role slug — even though the same cache already marks it
entitled: true. This path appears to trigger a live re-verification (matches idle gateway connections observed sitting inepoll_wait), which hangs or intermittently times out and falls back to the org default.
Suggested fix
- In the CLI's model resolution: when an org has
custom_role_configurationactive, canonicalize a bare model id to its corresponding@anthropic/<id>slug using data already present inmodelAccessCache/orgModelDefaultCache, rather than requiring an exact string match or triggering additional verification. - Bound whatever call the slow path makes with a timeout + clean fallback (matching what Desktop's UI eventually shows) — it should never hang indefinitely in
-p/scripted usage. - Separately, in Desktop: the native model picker should send the identifier form already known to work (the alias, or the exact
@anthropic/-prefixed slug it displays in its own picker UI) rather than constructing the bare canonical id when handing off to a remote-SSH session.
🤖 Generated with Claude Code