Model picker populates from unfiltered /v1/models, offering models the account policy blocks

Status Fixed / completed
Reported on v2.1.267
Maintainer reply None cached
Activity 1 comment · opened Sep 14, 2026 · closed Sep 14, 2026

TL;DR

With ANTHROPIC_BASE_URL pointed at an OpenAI-compatible gateway, the model
picker populates from the gateway's unfiltered catalog (/v1/models)
rather than the account-policy-filtered catalog (/v1/models/user). The
picker therefore offers models the account is forbidden to call, and selecting
one fails at inference with HTTP 404. Preferring /v1/models/user when the
endpoint exists would fix it.

A second, related finding: CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=0 does
not appear to govern the desktop picker at all.

Environment

  • Claude Code 2.1.267, running inside the Claude desktop app 1.52386.6
  • macOS 26.6.2 (Darwin 25.6.0), arm64
  • ANTHROPIC_BASE_URL=https://openrouter.ai/api
  • CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1
  • apiKeyHelper returns an OpenRouter key (sk-or-v1...)
  • The key's workspace has a zero-data-retention guardrail that excludes

non-Anthropic providers

Expected

The picker lists only models the account can actually call.

Actual

The picker lists Meta: Muse Spark 1.2 (and a 1M variant). Calling that model
returns HTTP 404. The entry is unusable but indistinguishable from a working
one until it fails.

Steps to reproduce

  1. Point ANTHROPIC_BASE_URL at an OpenAI-compatible gateway that serves both

/v1/models and an account-filtered /v1/models/user.

  1. Use an API key whose account policy blocks some providers the full catalog

advertises.

  1. Enable gateway model discovery.
  2. Open the model picker.
  3. Observe entries for blocked providers. Select one and send a message.

Evidence

All checks run against the same key, 2026-09-14.

| Check | Result |
|---|---|
| GET /v1/models (authenticated) | 445 models; 7 under meta/; includes meta/muse-spark-1.2 |
| GET /v1/models/user (authenticated) | 345 models; 1 under meta/ (muse-glimmer-30b); excludes meta/muse-spark-1.2 |
| POST /v1/messages meta/muse-spark-1.2 | HTTP 404 |
| POST /v1/messages anthropic/meta/muse-spark-1.2 | HTTP 404, same error |
| POST /v1/messages anthropic/claude-sonnet-5 | HTTP 200 |
| POST /v1/messages anthropic/claude-opus-4.8 | HTTP 200 |

The 404 body:

0 endpoints out of 1 requested are available matching your guardrail
restrictions and data policy. We removed them for the following reasons
(an endpoint may have matched multiple reasons):
ZDR violation (account settings): 1 endpoint excluded
ZDR violation (guardrail): 1 endpoint excluded

Every model shown in the picker is present in /v1/models. The one blocked
model shown, meta/muse-spark-1.2, is present only in /v1/models and not
in /v1/models/user. That asymmetry is the basis for concluding the picker
reads the unfiltered endpoint.

Two limits on that conclusion, stated so you can check them rather than take
them on trust. First, the mapping from picker label to catalog id is inferred
from display names, not read from the request. Second, the outgoing HTTP call
was never observed directly, so a third source that happens to contain
meta/muse-spark-1.2 cannot be ruled out from the outside. An exhaustive
search of on-disk config, application storage and the app bundle found no such
source, which is what makes the unfiltered endpoint the leading explanation
rather than a confirmed one. Whoever owns the code path can settle it in a
minute.

Second finding: the discovery flag does not govern the desktop picker

Setting CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=0 in
~/.claude/settings.json and fully restarting the app had no effect on the
picker. Verified:

  • The app relaunched as a new process, confirmed by new PID and start time.
  • The new process environment contained

CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=0, so the setting was applied.

  • The picker contents were unchanged.

Relatedly, ~/.claude/cache/gateway-models.json does not drive the picker.
Replacing its contents with a three-model list and fully restarting the app
left the picker showing four different models, none of which matched the file.
The file was not rewritten (mtime and checksum unchanged), so discovery did not
simply overwrite the edit. Whatever populates the picker is neither that cache
nor that flag.

Unexplained, lower confidence

anthropic/claude-sonnet-5 and anthropic/claude-opus-4.8 are present in the
gateway catalog and return HTTP 200 when called directly, but do not appear in
the picker, while claude-fable-5, claude-fable-5.1 and claude-opus-5 do.
No configuration file, application storage record, or bundled resource
containing the picker's list could be located. This may share a root cause with
the main report. It is recorded as an observation, not a diagnosis.

Suggested fix

Probe for /v1/models/user during gateway discovery and prefer it when it
returns successfully, falling back to /v1/models otherwise. This makes the
picker honor account policy by construction rather than surfacing entries that
fail only at call time.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗