Commit graph

1 commit

Author SHA1 Message Date
Tejas Chopra
2f2950a626
fix(litellm): don't forward a caller key the target cannot accept (#2883)
Split out of #2852 at review request: that PR is bounded upstream calls
plus
measured hot-path costs, and this is an authentication/routing change
that
belongs on its own scope. #2852 now carries only the timeout work.

## The bug

A routing extension can rewrite the model across families mid-request
(`claude-opus-5` → `gpt-5-mini`). The caller's key does not travel with
that
rewrite, so the proxy forwards `sk-ant-...` to OpenAI and earns a
guaranteed
401. Downstream that is indistinguishable from *"the cheap model failed
the
task"* — it scores as a quality regression against the router, not as a
bug.

Dropping the `api_key` kwarg instead lets litellm fall back to the
target
provider's own env credential, which is the only key that can work.

## Why this cut is different from the one that was rejected

The first version returned `not provider.startswith("anthropic")`, so
**any**
non-`sk-ant-` credential was dropped against an Anthropic-class target —
a
plain Bearer token against an Anthropic-compatible or custom gateway
lost its
key and fell back to an env credential that may not exist.

That direction is the dangerous one. A false refusal breaks a deployment
that
was working; a missed refusal just leaves today's 401. So this refuses
on
**positive evidence only**:

| credential | target | forwarded? |
|---|---|---|
| `sk-ant-…` | `openai` / `azure` / `gemini` | **no** — cannot possibly
authenticate |
| `sk-ant-…` | anthropic | yes |
| `sk-ant-…` | unrecognised / unclassifiable model | yes — pass-through
|
| anything else | anything | yes — pass-through, unchanged |

`sk-ant-` is Anthropic's documented vendor-specific prefix, which is
what makes
it classifiable. `sk-` is not: a dozen vendors mint that shape.
Everything the
string cannot settle keeps main's behaviour.

The reject list is explicit rather than inverted (`not anthropic`)
because an
unrecognised provider is usually a compatible or self-hosted gateway.
Marked in
the code as a hand-kept tuple with the registry-lookup upgrade path
noted.

Bedrock / Vertex / SageMaker are unaffected — all four dispatch sites
already
skip credential forwarding for them entirely (env-based auth).

## Verification

`tests/test_litellm_caller_key.py`, 12 cases — the refusal, the
Anthropic
target, the unknown provider, `get_llm_provider` raising, and each
unclassifiable credential shape asserted against **both** target
families.
Those last ones fail against the rejected version.

Applied at all four dispatch sites (Anthropic non-stream/stream, OpenAI
non-stream/stream).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 20:12:41 -07:00