diff --git a/src/anthropic/_client.py b/src/anthropic/_client.py index 76b840608..3f527902c 100644 --- a/src/anthropic/_client.py +++ b/src/anthropic/_client.py @@ -211,8 +211,8 @@ def __init__( or profile is not None ) if not has_explicit_credential: - api_key = os.environ.get("ANTHROPIC_API_KEY") - auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN") + api_key = os.environ.get("ANTHROPIC_API_KEY") or None + auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN") or None self.api_key = api_key self.auth_token = auth_token # --- end credentials support --- @@ -628,8 +628,8 @@ def __init__( or profile is not None ) if not has_explicit_credential: - api_key = os.environ.get("ANTHROPIC_API_KEY") - auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN") + api_key = os.environ.get("ANTHROPIC_API_KEY") or None + auth_token = os.environ.get("ANTHROPIC_AUTH_TOKEN") or None self.api_key = api_key self.auth_token = auth_token # --- end credentials support --- diff --git a/tests/test_client.py b/tests/test_client.py index b6ebf9e4d..61fd0994b 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -434,6 +434,17 @@ def test_validate_headers(self) -> None: request2 = client2._build_request(FinalRequestOptions(method="get", url="/foo", headers={"X-Api-Key": Omit()})) assert request2.headers.get("X-Api-Key") is None + def test_empty_string_env_credentials_treated_as_absent(self) -> None: + # An empty-string env var must not be used as a credential — it would + # produce a malformed "Authorization: Bearer " header rejected by h11. + with mock.patch("anthropic._client.default_credentials", return_value=None): + with update_env(ANTHROPIC_API_KEY="", ANTHROPIC_AUTH_TOKEN=""): + client = Anthropic(base_url=base_url, _strict_response_validation=True) + + assert client.api_key is None + assert client.auth_token is None + assert client.auth_headers == {} + def test_default_query_option(self) -> None: client = Anthropic( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} @@ -1546,6 +1557,17 @@ def test_validate_headers(self) -> None: request2 = client2._build_request(FinalRequestOptions(method="get", url="/foo", headers={"X-Api-Key": Omit()})) assert request2.headers.get("X-Api-Key") is None + def test_empty_string_env_credentials_treated_as_absent(self) -> None: + # An empty-string env var must not be used as a credential — it would + # produce a malformed "Authorization: Bearer " header rejected by h11. + with mock.patch("anthropic._client.default_credentials", return_value=None): + with update_env(ANTHROPIC_API_KEY="", ANTHROPIC_AUTH_TOKEN=""): + client = AsyncAnthropic(base_url=base_url, _strict_response_validation=True) + + assert client.api_key is None + assert client.auth_token is None + assert client.auth_headers == {} + async def test_default_query_option(self) -> None: client = AsyncAnthropic( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"}