You tried to run your Claude integration and got slapped with failed to connect to api.anthropic.com err_bad_request. I’ve been there. The good news is this error almost always comes from something you can fix in minutes, not hours.
The short answer: ERR_BAD_REQUEST means your HTTP request reached Anthropic’s servers but was rejected before it could be processed. The server understood your request, looked at it, and said no. That is not a network outage. That is not a firewall. Something in your request payload, headers, or authentication is malformed or invalid.
The Request Got Through, But Something Was Wrong With It
This distinction matters. A lot of people panic and start checking their internet connection or blaming Anthropic’s infrastructure. But ERR_BAD_REQUEST is an HTTP 400-level error. The connection itself succeeded. Your data traveled to Anthropic’s servers. The server read it, decided it was invalid, and refused it.
Compare that to a true connectivity failure, which would give you ERR_NAME_NOT_RESOLVED or a timeout. Those are different problems entirely. If you’re seeing ERR_BAD_REQUEST specifically, the server is reachable. Your request is the problem.
The most common culprits in 2026:
- Invalid or expired API key
- Malformed JSON in the request body
- Wrong model name or deprecated model string
- Incorrect
Content-Typeheader - Sending a
max_tokensvalue that exceeds the model’s limit - Missing required fields in the request body
- Sending an empty
messagesarray

Fix 1: Check Your API Key First
I cannot tell you how many times this is the actual problem. An invalid API key is the number one cause of ERR_BAD_REQUEST on the Anthropic API.
Check these things in order:
Is the key correctly formatted? Anthropic API keys start with sk-ant-. If yours starts with anything else, it’s wrong. If you’re copy-pasting from the Anthropic Console and accidentally grabbed extra whitespace, that breaks authentication immediately.
Is the key revoked or expired? Go to console.anthropic.com and check your API keys section. Keys can be manually revoked, or they expire if your account billing lapses. If the key shows as inactive, generate a new one.
Are you passing it correctly? The API key goes in the Authorization header as a Bearer token, and also in the x-api-key header for some SDK versions. Here’s the correct format:
Authorization: Bearer sk-ant-your-key-here
x-api-key: sk-ant-your-key-here
Is the key hardcoded vs environment variable? If you switched environments (dev to prod, local to staging), your environment variable might not be set. Print the key value before the request to confirm it’s loading correctly.
import os
api_key = os.environ.get("ANTHROPIC_API_KEY")
print(f"Key loaded: {bool(api_key)}, starts with: {api_key[:10] if api_key else 'NONE'}")
Fix 2: Validate Your Request Body
Anthropic’s API is strict about JSON structure. A single wrong field name or wrong data type will trigger ERR_BAD_REQUEST.
Here is the minimal valid request structure for the Messages API:
{
"model": "claude-opus-4-6",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "Hello, how are you?"
}
]
}
Every field matters. Here’s what breaks things:
| Common Mistake | What You Sent | What It Should Be |
|---|---|---|
| Wrong field name | "message" | "messages" (plural) |
| Wrong role value | "human" | "user" |
| Content as null | "content": null | "content": "your text" |
| Empty messages array | "messages": [] | At least one message |
| Missing max_tokens | No field at all | Required field |
| Wrong data type | "max_tokens": "1024" | "max_tokens": 1024 (integer) |
The max_tokens field must be an integer, not a string. I’ve seen this trip up developers who pull values from environment variables that return strings.
Fix 3: Use the Correct Model Name
Model strings change. If you’re using a model string from a tutorial you read six months ago, it may no longer be valid. Anthropic deprecates old model versions and the API will reject an unknown model name with a 400 error.
As of 2026, valid model strings for the Messages API include:
claude-opus-4-8claude-opus-4-7claude-opus-4-6claude-sonnet-4-6claude-haiku-4-5-20251001
Model names are case-sensitive. Claude-Sonnet-4-6 will fail. claude-sonnet-4-6 works.
Check the official Anthropic API documentation for the current model list. This is one page you should bookmark and revisit whenever you update your integration.
Fix 4: Set the Correct Headers
Missing or wrong headers cause 400 errors more than people expect. The Anthropic API requires two specific headers on every request:
Content-Type: application/json
x-api-key: your-api-key
Some older code examples only show Authorization: Bearer. That works for some endpoints but not all. The safest approach is to include both Authorization and x-api-key. Here is a complete Python example:
import requests
import json
headers = {
"Content-Type": "application/json",
"x-api-key": "sk-ant-your-key",
"anthropic-version": "2023-06-01"
}
payload = {
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Say hello"}]
}
response = requests.post(
"https://api.anthropic.com/v1/messages",
headers=headers,
data=json.dumps(payload)
)
print(response.status_code)
print(response.json())
The anthropic-version header is recommended. Omitting it sometimes causes unexpected behavior with newer API features.
Fix 5: Check max_tokens Against Model Limits
Every model has a maximum output token limit. If you set max_tokens higher than what the model supports, the API rejects the request with a 400 error.
| Model | Max Output Tokens |
|---|---|
| claude-opus-4-8 | 32,000 |
| claude-opus-4-6 | 32,000 |
| claude-sonnet-4-6 | 16,000 |
| claude-haiku-4-5 | 8,096 |
Setting max_tokens: 100000 on any current model will give you ERR_BAD_REQUEST. Keep your value within the model’s documented limit.
Fix 6: Inspect the Actual Error Response Body
People see ERR_BAD_REQUEST in their browser console or logs and stop there. But Anthropic’s API almost always returns a JSON error body that tells you exactly what went wrong. You need to read that body.
response = requests.post(url, headers=headers, json=payload)
if response.status_code != 200:
print(f"Status: {response.status_code}")
print(f"Error: {response.json()}")
The error response looks like this:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "max_tokens: field required"
}
}
That message field is your actual answer. “Field required”, “invalid model”, “string too long”, “invalid api key” are all specific messages that point you directly at the fix. Always log the full error response. Never just log the status code.
Fix 7: Proxy and Middleware Issues
If you’re running your Claude integration behind a proxy, a reverse proxy, or middleware that modifies requests, the request can be corrupted before it reaches Anthropic’s servers.
Symptoms that suggest a proxy problem:
- It works when you call the API directly from your machine but fails in production
- It works in curl but fails in your application
- The error appeared after deploying to a new environment
Things to check:
- Is your proxy modifying the
Content-Typeheader? - Is your proxy stripping the
x-api-keyheader for security reasons? (Some corporate proxies strip custom headers) - Is your proxy double-encoding the JSON body?
- Are there SSL inspection tools that might be interfering with the TLS connection?
To test, try making the same API call with curl directly from the server where your application runs:
curl https://api.anthropic.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-sonnet-4-6","max_tokens":100,"messages":[{"role":"user","content":"hi"}]}'
If curl works but your app doesn’t, the problem is in your application layer or proxy, not in your API credentials or payload logic.
Fix 8: Rate Limits vs Bad Request Errors
A common confusion: rate limit errors come back as HTTP 429, not 400. If you’re seeing a 400 ERR_BAD_REQUEST, it’s not a rate limit problem. Do not add retry logic as your first response to a 400. Fix the request first.
That said, here is a comparison so you know what you’re dealing with:
| Error Code | Meaning | What to Do |
|---|---|---|
| 400 Bad Request | Your request is malformed | Fix the request structure, headers, or auth |
| 401 Unauthorized | API key invalid or missing | Check and replace your API key |
| 403 Forbidden | No permission for this action | Check your account plan and permissions |
| 429 Too Many Requests | Rate limit hit | Implement backoff and retry logic |
| 500 Internal Server Error | Anthropic server issue | Retry with exponential backoff |
| 529 Overloaded | API capacity issue | Wait and retry |
Only HTTP 500 and 529 warrant automatic retries. A 400 will fail every single time until you fix what’s wrong with your request.
SDK-Specific Issues in 2026
If you’re using the official Anthropic Python or TypeScript SDK rather than raw HTTP calls, some additional things can trigger this error.
Python SDK:
import anthropic
client = anthropic.Anthropic(api_key="sk-ant-your-key")
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
SDK version mismatches cause problems. An old version of the SDK might not support new model names or new API features. Run pip show anthropic to check your version, then pip install --upgrade anthropic to update.
JavaScript/TypeScript SDK:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const message = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
The same versioning advice applies. Check npm list @anthropic-ai/sdk and update if you’re behind.
A subtle issue specific to Node.js: if you’re loading environment variables with dotenv and calling new Anthropic() before dotenv.config() runs, the API key will be undefined and you’ll get a 400 or 401 error.
import dotenv from "dotenv";
dotenv.config(); // This must come FIRST
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // Now it can read ANTHROPIC_API_KEY
Debugging Checklist
Before spending more time debugging, run through this list in order. Most people find their answer in the first three items.
- Print the exact API key being used (first 10 characters is enough to verify it loaded)
- Print the exact JSON payload being sent, formatted, before the request fires
- Check the response body, not just the status code
- Verify the model name against the current documented model list
- Confirm
max_tokensis an integer within the model’s limit - Confirm
Content-Type: application/jsonis in your headers - Confirm
messagesis an array with at least one object - Confirm each message object has both
roleandcontentfields - Test the same request with curl from the same server
- Check for proxy or middleware that might modify requests
The Anthropic developer community forum at community.anthropic.com is genuinely useful for edge cases. If you’ve gone through this full list and still can’t reproduce the fix, posting your exact error response body there usually gets a quick answer.
Conclusion
Failed to connect to api.anthropic.com err_bad_request sounds like a connection problem but it isn’t. The connection works. Something in your request is invalid. In 90% of cases it’s one of four things: bad API key, wrong model name, malformed JSON body, or missing required fields.
Start by printing the actual error message from the response body. That single step eliminates half the guesswork. Then work through the checklist above in order. You do not need to guess. The API tells you what’s wrong if you read what it says back.
FAQs
My code worked yesterday and now I’m getting this error. What changed?
This usually means your API key was revoked or your account billing lapsed. Log into the Anthropic Console and check your key status and billing. It can also happen if Anthropic deprecated a model string you were using. Check the model name in your code against the current model list.
I’m getting ERR_BAD_REQUEST only in production, not locally. Why?
Your production environment is likely missing an environment variable, running an older SDK version, or sitting behind a proxy that strips headers. Run the curl test directly on your production server to isolate the issue. If curl works on the server but your app doesn’t, the problem is in your application code or middleware layer.
Can a system prompt cause a 400 error?
Yes. If your system prompt is extremely long and exceeds the model’s context window when combined with your messages, you’ll get a 400 error about token count. Also, passing null or an empty string as the system prompt value (instead of omitting the field entirely) can cause a validation error on some API versions.
Does the order of messages in the array matter?
It does. The Messages API requires that roles alternate between user and assistant. Sending two consecutive user messages without an assistant message in between will trigger a 400 error. The array must start with a user message and follow the alternating pattern.
I’m using a third-party tool that calls the Anthropic API. Can I still fix this?
If you control the API key, check that it’s valid in the Anthropic Console. If the tool is open source, check its GitHub issues for known bugs with the current API version. If it’s a closed-source SaaS tool, contact their support and share the exact error message from your logs. The error response body will tell their team exactly what’s going wrong on their end.
