406 Error Code | Fix Not Acceptable Fast

The 406 Error Code means the server can’t return content that matches your request headers, most often the Accept or Content-Type.

A 406 response can feel odd because the site is online, yet your browser, app, or script gets blocked. The server is simply saying it can’t produce a response in any format you said you’ll accept.

This guide walks you through what 406 is, why it shows up, and the exact checks that clear it. You’ll see quick client fixes, server configuration traps, and API tips you can apply in minutes.

What A 406 Response Means In Plain Terms

HTTP 406 is the status code for “Not Acceptable.” It’s part of HTTP content negotiation. Your client sends headers that describe the response formats it can handle. The server picks a format it can generate. When there’s no overlap, the server may return 406.

The header that triggers 406 most often is Accept. A strict server might require a match like application/json or text/html. If your client sends something too narrow, or sends a value the server doesn’t serve, you get 406.

406 can appear in a browser, yet it shows up more in APIs and in apps that sit behind proxies, CDNs, WAF rules, or API gateways. Those layers sometimes rewrite headers or enforce allowlists for media types.

406 Error Code In APIs And Browsers

You’ll meet 406 in one of these patterns. Spotting the pattern saves time because you can target the right layer .

  • Browser hits a page — A plug-in, extension, or privacy tool injects headers that a strict server rejects, or the server is set to serve only a small set of content types.
  • API client gets blocked — The client asks for XML, a custom vendor type, or a wildcard format that the server refuses, so the server declines the request.
  • Reverse proxy sits in front — Nginx, Apache, a load balancer, or a gateway strips or replaces Accept and Content-Type, changing what the upstream sees.
  • Framework enforces format rules — Some routes are configured to answer only JSON. If a request says it only accepts HTML, the framework refuses the match.

Keep one rule in mind: 406 is about what the server can send back. It is not a “bad request body” code. When the request body is the issue, you’ll more often see 400, 415, or 422, depending on the stack.

Common Triggers That Produce A 406

Most 406 cases come from a small set of causes. Run through these from fastest to slowest, starting with what you can control.

Accept Header Too Narrow

If your client sends Accept: application/xml and the endpoint only serves JSON, there’s no shared format. Some servers will still reply with JSON. Strict servers reply with 406.

  • Send a broader Accept — Try Accept: application/json or Accept: */* to confirm negotiation is the issue.
  • Match the endpoint format — If docs say JSON only, set JSON and stop sending extra types.

Content-Type And Accept Mixed Up

It’s easy to confuse request and response headers. Content-Type describes the body you send. Accept describes the body you want back. A client that sets Accept to the same value as Content-Type can break an endpoint that returns a different type.

  • Set Content-Type for the body — Use Content-Type: application/json only when you’re sending JSON in the request.
  • Set Accept for the response — Use Accept: application/json when you expect JSON back.

Route Or Controller Format Constraints

Many frameworks let you constrain a route by format. A route might be declared as “JSON only,” or it might infer format from a URL suffix like .json. When the route and the request headers disagree, the route may not match and the framework can answer with 406.

  • Check route constraints — Look for format guards, MIME allowlists, or “produces” annotations.
  • Try the explicit URL — If the app uses suffixes, test /resource.json or the documented variant.

Security Rules Blocking Certain Types

WAF rules, gateways, and CDNs can block response formats they don’t want to serve, or they may refuse requests with uncommon Accept values to reduce abuse. If 406 appears only in production, and not in local runs, suspect the edge layer.

  • Compare headers across environments — Capture the request headers in dev and prod and look for differences.
  • Review WAF allowlists — Check whether vendor media types or wildcards are rejected.

Fast Client Checks That Clear Most 406s

Start here if you are the one calling the endpoint, or if you can reproduce the error from your own machine. These checks keep you from chasing server config when the client is the source.

  1. Reproduce with curl — Send the same URL with a request, then add headers one by one until 406 appears.
  2. Test a permissive Accept — Use Accept: */* as a quick probe. If it works, tighten the value to the real format the server returns.
  3. Remove custom media types — If you send values like application/vnd.company+json, switch to application/json to confirm the server handles the vendor type.
  4. Drop browser extensions — Open an incognito window with extensions off, then retest. Some tools inject headers or rewrite requests.
  5. Check cached headers in tooling — API clients can reuse headers from a prior request. Clear the tab, create a fresh request, then set headers from scratch.

If the error only hits one device or one network, compare the exact request headers. A proxy, VPN, or corporate gateway can add headers you never set.

Server-Side Fixes That Stop 406 At The Source

If you own the server, you can turn a fragile setup into a forgiving one. The goal is not to answer every possible format. The goal is to answer the formats you actually intend to serve, and to treat harmless header quirks with grace.

Confirm The Endpoint’s Response Type

Check what the endpoint really returns when called without extra headers. Many APIs return JSON by default. Many web routes return HTML by default. If the endpoint is supposed to return JSON, make sure it declares that clearly in your code and in your gateway settings.

  • Log the negotiated type — Record the chosen response content type and the incoming Accept header for 406 responses.
  • Serve a sensible default — If a route can return JSON and HTML, pick a default when the client sends Accept: */*.

Relax Over-Strict Content Negotiation

Some stacks treat a missing Accept header as “accept nothing,” which is rare but real. Others treat an unrecognized value as a hard fail. If you’re seeing 406 from regular browsers, your negotiation rules may be too strict for the public web.

  • Allow common wildcards — Accept values like */* and text/* when they map cleanly to your output.
  • Keep the allowlist short — Stick to formats you serve and test, like application/json and text/html.

Check Proxy And CDN Header Handling

A proxy can change headers on the way in. It can also change the response headers on the way out. When that happens, the upstream app may behave as if the client asked for something else.

  • Pass Accept through — Confirm your proxy forwards Accept and doesn’t overwrite it with a fixed value.
  • Disable MIME rewrites — Turn off rules that force a response type that your app does not generate.
  • Validate cache variations — If you vary cache by Accept, confirm the cache identifier matches the formats you intend to serve.

Use This Triage Table To Pinpoint The Layer

This table helps you map a symptom to the likely spot to check first.

What You See Most Likely Cause First Fix To Try
Works with Accept: */* Accept value too narrow Set Accept to the real response type
Fails only behind a proxy Header rewrite or allowlist Forward Accept unchanged
Fails only on one route Route format constraint Update route “produces” rules
Fails only in production Edge security rule Adjust WAF rule for media types

Reliable Fix Patterns For Popular Stacks

You don’t need a full rewrite to stop 406. Small, targeted changes usually do it. Start with logs, then apply the smallest fix that makes the endpoint consistent.

REST APIs Returning JSON

  1. Return JSON on errors — If your error handler returns HTML while your API routes return JSON, clients that accept JSON only can trip 406 on error paths.
  2. Set response Content-Type — Make sure responses include Content-Type: application/json so clients can parse them without guessing.
  3. Document the required Accept — If your API requires application/json, state it and test it in client samples.

Web Pages Returning HTML

  1. Stop rejecting browser Accept lists — Browsers send long Accept headers with multiple types and quality values. Ensure your server treats text/html as a match even when it appears with other types.
  2. Check language and encoding rules — If you enforce Accept-Language or Accept-Charset strictly, loosen the matching so normal browsers still pass.
  3. Serve a default page type — If a route is meant to be HTML, serve HTML when Accept is missing or broad.

Gateway And WAF Setups

  1. Allow common vendor JSON — If your clients use vendor types, permit them when they map to JSON and your app can handle them.
  2. Keep rules consistent across stages — Match dev and prod rules so you don’t ship a route that only fails after release.
  3. Add a header audit log — Store the original request headers at the edge so you can compare them with what your app receives.

A Practical Debug Flow You Can Reuse

When you see the 406 error code again, use this flow and you’ll usually get to the fix without guesswork.

  1. Capture the full request — Save method, URL, and headers. Include what your proxy adds.
  2. Confirm the response type you expect — Decide whether the route should return JSON, HTML, or something else.
  3. Make the client request match — Set Accept to that type, then test.
  4. Check the first hop — If you use a gateway or proxy, verify it forwards headers and doesn’t enforce a conflicting rule.
  5. Make the server consistent — Align normal responses and error responses to the same content type for that endpoint.

Once you’ve fixed the mismatch, add a small guardrail. A unit test that checks response Content-Type, plus a log line on 406, will keep the issue from sneaking back in during later changes.

If you only take one action today, run a clean request with a permissive Accept value. It quickly tells you if negotiation is the culprit. Then lock the headers to the format your endpoint actually serves, and the 406 error code should stop showing up.

In logs, treat 406 as a format mismatch: the Accept rules didn’t match what the server can send.