Skip to content

fix(client): treat empty-string env credentials as unset#1673

Open
Zawwarsami16 wants to merge 2 commits into
anthropics:mainfrom
Zawwarsami16:fix/empty-string-credentials
Open

fix(client): treat empty-string env credentials as unset#1673
Zawwarsami16 wants to merge 2 commits into
anthropics:mainfrom
Zawwarsami16:fix/empty-string-credentials

Conversation

@Zawwarsami16

Copy link
Copy Markdown

Summary

Closes #1640.

When ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN are present in the environment but set to an empty string, the client treats the empty value as a real credential rather than as absent. It then builds an Authorization: Bearer header (literally Bearer + trailing space) and an empty X-Api-Key. The HTTP layer (h11, via httpx) validates header values at write time and rejects the trailing space, so every request fails:

h11._util.LocalProtocolError: Illegal header value b'Bearer '

surfaced as anthropic.APIConnectionError. Empty-string env vars are common in CI, containers, and wrapper shells (export VAR=), and the Claude Code CLI exports both ANTHROPIC_AUTH_TOKEN= and ANTHROPIC_API_KEY= empty — so any script there that constructs Anthropic() without an explicit key fails on every call.

Root cause

The env-credential guards use is None, so an empty string slips through every check: the env read keeps "", the "missing auth" fallback (api_key is None and auth_token is None) never fires, and the header builders emit on is not None — producing {"X-Api-Key": "", "Authorization": "Bearer "}.

Fix

Coerce an empty env credential to None at read time in both the sync and async clients, so an empty value is treated as unset and credential auto-discovery runs as expected. Explicitly-passed credentials are untouched.

api_key = os.environ.get("ANTHROPIC_API_KEY") or None
auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN") or None

Verification

Reproduced the LocalProtocolError on main before the change; after the fix auth_headers == {} and auto-discovery runs. A real key still produces the correct X-Api-Key header.

  • Added regression tests for both sync and async clients (tests/test_client.py).
  • pytest tests/test_client.py — 170 passed.
  • ruff check / ruff format --check clean; no new pyright errors on changed lines.

When ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN are present in the
environment but set to an empty string, the SDK treated the empty string
as a real credential (guards use `is None`). It then built an
`Authorization: Bearer ` header (trailing space) and an empty
`X-Api-Key`, which the HTTP layer (h11) rejects at write time, failing
every request with a confusing APIConnectionError.

Empty-string env vars are common in CI, containers, and wrapper shells
(e.g. `export VAR=`, and the Claude Code CLI exports both empty). Coerce
an empty env credential to None at read time so it is treated as absent
and credential auto-discovery runs as expected.
@Zawwarsami16 Zawwarsami16 requested a review from a team as a code owner June 13, 2026 09:07
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.

Anthropic() emits a malformed Authorization: Bearer header when ANTHROPIC_AUTH_TOKEN is an empty string

1 participant