Skip to content

fix(routing): 404 model ids without the canonical 3-segment namespace - #127

Merged
robmsmt merged 1 commit into
mainfrom
fix/enforce-namespaced-model-ids
Aug 11, 2026
Merged

fix(routing): 404 model ids without the canonical 3-segment namespace#127
robmsmt merged 1 commit into
mainfrom
fix/enforce-namespaced-model-ids

Conversation

@robmsmt

@robmsmt robmsmt commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Anyone sending a model id that is not exactly <namespace>/<model_org>/<model_name> now gets a 404 at the request boundary, before any routing decision. Previously, bare upstream ids like swiss-ai/Apertus-8B-Instruct-2509 were silently claimed by the first registered passthrough provider that advertised them (CSCS L1 today) — which provider won was an accident of registration order.

  • New backend/middleware/model_id.pyrequire_namespaced_model(): accepts exactly three non-empty slash-separated segments (SwissAI-Research/..., CSCS-Inference/..., RCP-AIaaS/..., or <username>/... user launches); anything else 404s with the expected form in the error message, and logs a warning so operators can spot unmigrated clients.
  • Enforced on every model-forwarding endpoint: /v1/chat/completions, /v1/completions, /v1/responses, /v1/embeddings, /v1/rerank, /v1/score, /v1/classify, /v1/tokenize, /v1/detokenize.
  • The bare-id back-compat loop in resolve_model is now unreachable and removed — no more silent first-provider-wins rerouting.

Supersedes #125 (that PR removed the rerouting inside resolve_model only; this enforces the invariant for all traffic at the boundary). Recommend closing #125 if this lands.

Client impact

  • Bare ids (the historical swiss-ai/Apertus-* form) and ids with missing/extra segments now 404 with: Model '...' not found. Model ids must be fully namespaced as <namespace>/<model_org>/<model_name> ....
  • Requests that omit model entirely also get this 404 instead of an opaque upstream error.
  • One caveat to verify before merge: if a passthrough upstream ever advertises a single-segment id (e.g. a hypothetical CSCS-Inference/glm-4.5), its prefixed form has only 2 segments and would be listed in /v1/models but unroutable. Current CSCS/RCP catalogs use HF-style org/name ids, so today's models are all fine.

Tests

  • test_model_id_validation.py: valid/invalid shape matrix for the helper + a router-level test proving a bare id 404s before _resolve_route is ever called.
  • Passthrough tests updated: bare ids resolve to None; cross-provider collision test asserts the bare id routes to neither.
  • test_app.py pooling/classify fixtures moved to namespaced ids (they used single-segment "m").
  • Full suite: 141 passed; ruff clean.

🤖 Generated with Claude Code

Every routable id on the platform is <namespace>/<model_org>/<model_name>
(SwissAI-Research/..., CSCS-Inference/..., RCP-AIaaS/..., or a username
for user launches). Ids with any other shape — notably historical bare
upstream ids like swiss-ai/Apertus-8B-Instruct-2509 — used to be
silently claimed by the first registered passthrough provider that
advertised them, with registration order picking the winner.

Enforce the shape at the request boundary instead: a new
require_namespaced_model helper 404s malformed ids (with the expected
form in the message and a warning log for operators) across chat
completions, completions, responses, embeddings, rerank, score,
classify, tokenize and detokenize. The bare-id back-compat loop in
resolve_model is now unreachable and removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@FarukZahiragic FarukZahiragic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@robmsmt
robmsmt merged commit bdc4175 into main Aug 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants