◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-04-10Beginner

How to Fix Claude API 401 Invalid API Key Authentication Error

Complete guide to fixing Claude API 401 Invalid API Key errors. Covers environment variable issues, expired keys, OAuth token corruption, proxy interference, and more with step-by-step solutions.

troubleshooting92error17fix12api39authentication5401

Symptoms of the 401 Authentication Error

When working with the Claude API, you may encounter a frustrating 401 Invalid API Key error — whether you're just getting started or have had things running smoothly for weeks. The error typically looks like this in your terminal or logs:

{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API Key"
  }
}

This error means the API key sent with your request was rejected. But the root cause isn't always as simple as a typo in your key. It could be a misconfigured environment variable, an expired key, a corrupted OAuth token, or even network interference.

Cause 1: API Key Not Properly Configured

The most frequent culprit is a missing or incorrect ANTHROPIC_API_KEY environment variable.

How to Check

Run this in your terminal to see what's currently set:

# Check if the environment variable exists (show first 10 characters only)
echo "${ANTHROPIC_API_KEY:0:10}..."
 
# If empty, the variable isn't set

If the output is blank or doesn't start with sk-ant-, there's a configuration issue.

How to Fix It

# macOS / Linux: Add to your shell config
echo 'export ANTHROPIC_API_KEY="sk-ant-api03-xxxxx..."' >> ~/.zshrc
source ~/.zshrc
 
# Windows (PowerShell): Set as user environment variable
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-api03-xxxxx...", "User")
# Restart PowerShell to apply

Common pitfall: You might have added the key to a .env file, but your application isn't loading it. In Python, make sure you're using python-dotenv; in Node.js, use the dotenv package. Double-check that the .env file is in the correct directory.

# Python: Verify .env file loading
import os
from dotenv import load_dotenv
 
load_dotenv()  # Load .env file
 
api_key = os.getenv("ANTHROPIC_API_KEY")
if not api_key:
    raise ValueError("ANTHROPIC_API_KEY is not set")
 
print(f"API Key found: {api_key[:10]}...")
# Expected output: API Key found: sk-ant-api...

Cause 2: API Key Has Been Revoked or Expired

If someone on your team regenerated or deleted the key in the Anthropic Console, the old key becomes invalid immediately. This can happen without notice in shared workspace environments.

How to Check

  1. Log in to the Anthropic Console
  2. Navigate to the "API Keys" section
  3. Confirm that your key is listed and its status shows "Active"

How to Fix It

If the key is missing or inactive, create a new one and update your configuration:

# Set the new key
export ANTHROPIC_API_KEY="sk-ant-api03-your-new-key..."
 
# Quick verification with curl
curl -s https://api.anthropic.com/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 50,
    "messages": [{"role": "user", "content": "Hello"}]
  }' | head -c 200
 
# Expected output: {"id":"msg_...","type":"message","role":"assistant",...}

If you get a valid response, the new key works. Don't forget to update your .env files, CI/CD secrets, and any secret management tools with the new key.

Cause 3: Incorrect Request Header Format

The Claude API uses a different authentication header than many other AI APIs. If you're coming from OpenAI, you might instinctively use Authorization: Bearer, but Claude requires the x-api-key header instead.

Common Mistake vs. Correct Approach

import anthropic
 
# ❌ Wrong: Using Authorization Bearer header directly
# requests.post(url, headers={"Authorization": f"Bearer {api_key}"})
 
# ✅ Correct: Use the Anthropic SDK (handles x-api-key automatically)
client = anthropic.Anthropic()  # Reads ANTHROPIC_API_KEY from environment
 
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Hello!"}
    ]
)
print(message.content[0].text)
# Expected output: Hello! How can I help you today?

If you're making raw HTTP requests without the SDK, always include these headers:

# Required headers
-H "x-api-key: YOUR_API_KEY"
-H "anthropic-version: 2023-06-01"
-H "Content-Type: application/json"

Cause 4: Claude Code OAuth Token Corruption

Claude Code (the CLI tool) uses browser-based OAuth authentication via the /login command. When this token gets corrupted, you'll see a "401 Invalid bearer token" error even though the login appeared to succeed.

Symptoms

$ claude
⎿ API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"Invalid bearer token"}}

How to Fix It

Clear your credentials completely and re-authenticate:

# Step 1: Clear all authentication data
rm -rf ~/.claude/auth* 2>/dev/null
rm -rf ~/.claude/.credentials 2>/dev/null
 
# Step 2: Unset any API key that might conflict with OAuth
unset ANTHROPIC_API_KEY
 
# Step 3: Re-authenticate
claude /login
 
# Step 4: Complete browser auth, then verify
claude "Hello, this is a test"

If the issue persists, update Claude Code to the latest version:

# Update Claude Code
npm install -g @anthropic-ai/claude-code@latest
 
# Check version
claude --version

Cause 5: Proxy, VPN, or Firewall Interference

Corporate networks, certain countries, and VPN configurations can intercept or modify API requests, stripping or altering the authentication header before it reaches Anthropic's servers.

How to Check

# Check proxy settings
echo "HTTP_PROXY: $HTTP_PROXY"
echo "HTTPS_PROXY: $HTTPS_PROXY"
echo "NO_PROXY: $NO_PROXY"
 
# Direct connection test (bypass proxy)
curl -v --noproxy '*' https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-sonnet-4-6","max_tokens":10,"messages":[{"role":"user","content":"Hi"}]}' \
  2>&1 | grep -E "HTTP/|error|auth"

How to Fix It

If the direct connection test works but proxied requests fail, add api.anthropic.com to your proxy bypass list:

# Add api.anthropic.com to proxy bypass
export NO_PROXY="api.anthropic.com,$NO_PROXY"

For VPN users, temporarily disconnect and test to isolate whether the VPN is causing the problem.

Cause 6: Billing or Permission Issues

Your API key might be valid, but access can still be denied due to account-level problems:

  • Zero credit balance: Pay-as-you-go accounts with no remaining credits
  • Key scope restrictions: Using a key from one workspace in a different workspace
  • Account suspension: The account has been suspended for policy violations

How to Check

  1. Log in to the Anthropic Console
  2. Navigate to "Billing" and check your credit balance
  3. Check "Settings" for account status
  4. Verify that the API key's workspace matches the one you're using

If your balance is depleted, adding credits will immediately restore access.

Verifying the Fix

After applying a fix, run this verification script to confirm everything is working:

import anthropic
import sys
 
def verify_authentication():
    """Verify Claude API authentication is working"""
    try:
        client = anthropic.Anthropic()
        
        # Minimal request to test auth
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=20,
            messages=[{"role": "user", "content": "Say OK"}]
        )
        
        print(f"✅ Authentication successful")
        print(f"   Model: {response.model}")
        print(f"   Response: {response.content[0].text}")
        print(f"   Usage: input={response.usage.input_tokens}, output={response.usage.output_tokens}")
        return True
        
    except anthropic.AuthenticationError as e:
        print(f"❌ Authentication error: {e}")
        print("   → Check your API key")
        return False
    except anthropic.APIConnectionError as e:
        print(f"❌ Connection error: {e}")
        print("   → Check your network settings")
        return False
    except Exception as e:
        print(f"❌ Unexpected error: {e}")
        return False
 
if __name__ == "__main__":
    success = verify_authentication()
    sys.exit(0 if success else 1)
 
# Expected output:
# ✅ Authentication successful
#    Model: claude-sonnet-4-6
#    Response: OK
#    Usage: input=10, output=3

Best Practices for Preventing Authentication Errors

Adopting a few good habits will save you from encountering these errors repeatedly.

Secure key management is the foundation. Never hardcode API keys in source code. Use environment variables or dedicated secret management tools like AWS Secrets Manager, HashiCorp Vault, or 1Password. In team settings, issue individual keys per developer rather than sharing a single key.

Robust error handling is equally important. Rather than blindly retrying on a 401 error, implement logic that verifies the key's validity before attempting again:

import anthropic
import time
 
def call_with_auth_retry(client, max_retries=2, **kwargs):
    """Retry with key re-validation on authentication errors"""
    for attempt in range(max_retries + 1):
        try:
            return client.messages.create(**kwargs)
        except anthropic.AuthenticationError:
            if attempt < max_retries:
                print(f"Auth error (attempt {attempt + 1}/{max_retries + 1})")
                print("Reloading API key...")
                # Reload from environment
                import os
                os.environ.pop("ANTHROPIC_API_KEY", None)
                from dotenv import load_dotenv
                load_dotenv(override=True)
                client = anthropic.Anthropic()
                time.sleep(1)
            else:
                raise

Looking back

The Claude API 401 authentication error is usually straightforward to resolve once you've identified the root cause. This guide covered six common patterns: missing environment variables, revoked keys, incorrect header format, corrupted OAuth tokens, proxy interference, and billing issues. Work through them in order, and you'll have your API calls running smoothly again.

The fastest troubleshooting approach: start with echo $ANTHROPIC_API_KEY to verify the key exists, then use a curl command to test directly. If that doesn't resolve things, use the Python verification script from this article.

For a comprehensive overview of error handling strategies, see our Claude API Error Handling and Retry Strategies guide. If you're just getting started with the API, our First API Call Troubleshooting FAQ covers the most common beginner pitfalls.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Claude Code2026-05-02
Stop the 'old_string is not unique' Error in Claude Code's Edit Tool — A Practical Rewrite Strategy
When Claude Code's Edit tool throws 'old_string is not unique in the file', the root cause is usually that the prompt didn't guarantee a uniquely identifiable target. Here's how to design rewrites that actually stick.
⬡ API & SDK2026-09-02
The 400 that rejects a thinking block, and finding the edit that caused it
On Claude Fable 5.1, editing the system prompt, tools, or earlier messages before a thinking block makes the request fail with a 400. Here is how to check whether your own agent loop does that in a single request, and how to move a rebuilt system prompt and client-side trimming to patterns that leave the prefix untouched.
⬡ API & SDK2026-05-22
Designing a Model-Selection Fallback That Survives this model is currently unavailable on Claude API
When Claude API answers 'this model is currently unavailable', treating it like a 529 Overloaded or a rate limit sends you the long way round. Here is how I tell the rejections apart by SDK exception class, switch model IDs per request, and the assumptions I had to fix along the way.