How to Fix the ‘406 Error’ in Python
The ‘406 Error’ (Not Acceptable) in Python requests library typically occurs during content negotiation failure, meaning the server cannot provide data in the format your client specified in its Accept headers. To fix this, you must adjust your request headers to match the content types the server can deliver.
Understand Define a 406 Error
Here a blog in Markdown (coding-friendly) about How to Fix the ‘406 Error’ in Python, meeting your criteria:
## Client-Side Fixes in Python – Adjusting Your Request
### Adjusting the `Accept` header
Start by looking at what your Python code is sending. For example with `requests`:
```python
import requests
url = "https://example.com/api/data"
headers = {"Accept": "application/json"} # you guessed JSON
response = requests.get(url, headers=headers)
print(response.status_code, response.headers.get("Content-Type"))
If the server returns 406, broaden your Accept header:
headers = {
"Accept": "application/json, text/html, */*; q=0.8",
"User-Agent": "python-requests/2.x"
}
response = requests.get(url, headers=headers)
Use a proper User Agent and minimal headers:
Sometimes the server rejects “unknown” clients. So set a more standard User-Agent:
headers["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " \
"(KHTML, like Gecko) Chrome/118.0 Safari/537.36"
Try another library if needed:
With httpx:
import httpx
with httpx.Client(headers=headers) as client:
resp = client.get("https://example.com/api/data")
print(resp.status_code, resp.headers.get("content-type"))
Or with aiohttp for async code:
import aiohttp
import asyncio
async def fetch():
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get("https://example.com/api/data") as r:
print(r.status, await r.text()[:200])
asyncio.run(fetch())
Fallback if you can’t control the server:
If you cannot change the server, you can allow the client to accept whatever the server sends and then post-process it. For instance, let Accept: */*, get back text/html, parse it anyway.
Server Side Fixes in Python Frameworks
Flask example:
If you’re writing a Flask API and users complain about 406:
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
@app.route("/items")
def items():
accept = request.headers.get("Accept", "*/*")
if "application/json" not in accept and "*/*" not in accept:
abort(406)
return jsonify(items=["apple","banana"])
You can make it more forgiving:
@app.route("/items")
def items():
# Always return JSON, regardless of Accept
return jsonify(items=["apple","banana"])
FastAPI example:
FastAPI performs media type negotiation by default. If you get 406:
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/items")
async def items(request: Request):
if "application/json" not in request.headers.get("accept", "*/*"):
raise HTTPException(status_code=406, detail="Not acceptable")
return JSONResponse({"items": ["apple","banana"]})
You could loosen it by ignoring the Accept header, or by adding extra response types.
Django REST Framework (DRF) example:
In DRF, the renderer classes determine what you can send back. If your client requests a format your API doesn’t support, DRF may return 406. In settings.py:
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": [
"rest_framework.renderers.JSONRenderer",
"rest_framework.renderers.BrowsableAPIRenderer",
],
}
Ensure your renderer list covers what clients will ask for, or catch unsupported requests and return a custom response rather than generic 406.
Diagnosing & Debugging the 406 Error
Log what headers you send and receive:
On the client side, print request headers. On the server side, log the received headers and available response types. The mismatch often shows immediately.
Test in a browser first:
If the URL works fine in the browser but your Python code returns 406, open DevTools → Network → see what the browser sends vs what your code sends. Then mimic the browser’s headers.
Minimal reproducible script:
Shrink your code to minimal form: only one GET request, one header. If it runs cleanly, you know your larger code introduced something extra.
Check server logs for content negotiation:
Look for messages where the server says “requested media type X not supported” or similar.
Confirm server response types:
If you’re the server maintainer, document or log what content types your endpoints support. If you’re client only, try hitting the endpoint via curl or httpie with Accept: */* and inspect the Content-Type header of successful responses.
Preventing 406 Errors in Future Python Projects
When developing Python clients or APIs:
- Default to
Accept: application/json, */*or a similar flexible header unless you know exactly what the server wants. - On server side, provide a default representation when a client’s Accept header is too restrictive, rather than returning 406 immediately. This keeps things smoother for many clients.
- When designing an API, document clearly what
Accept,Accept-Language,Accept-Encodingyour endpoints support. - Use browser dev tools or
curlto inspect successful header sets and mirror them in your code. - For scraping or automation, treat the User-Agent header and other “bot-detection” signals as part of the negotiation landscape.
- In async or high performance code, minimize extra headers and keep the request lean—excessive or odd headers increase odds of mismatch.
Conclusion
The 406 Not Acceptable error may seem like a weird, rare beast, but in the context of Python it often boils down to a mismatch between what your code asks for and what the server is willing to give. Here you’ve learned how to fix the error from both the client side and server side, how to debug it in real Python environments, and how to set yourself up so it rarely happens again. With the added context of competitive articles and the extra Python-specific insights you now have, you’re in a stronger place than many guides out there. Next time a 406 pops up, you’ll know exactly where to look, what to tweak, and how to restore smooth communication between your Python app and the server.