Your deploy looked clean. Health checks passed. Then the first real request hit the API and came back with error code 415. The payload looked valid, the endpoint existed, auth was fine, and yet the service refused to touch the body.
That's the kind of failure that burns time because it sits in the gap between client code, middleware, proxies, and browser behavior. A common initial check involves Content-Type, which is right, but it's not the whole story. A stubborn 415 can also come from Content-Encoding, strict endpoint media rules, or a browser implicitly downgrading your request to text/plain.
Table of Contents
- Understanding the HTTP 415 Unsupported Media Type Error
- Diagnosing Client-Side Causes and Fixes
- Fixing Common Server-Side Configuration Issues
- Troubleshooting Advanced Scenarios with Encoding and Proxies
- Detecting and Triaging 415 Errors with Log Management
- Proactive Prevention and Alerting Strategies
- Frequently Asked Questions About HTTP 415
Understanding the HTTP 415 Unsupported Media Type Error
HTTP 415 Unsupported Media Type means the server refused the request because it couldn't accept the message format being sent. MDN describes it as a client error response caused by an unsupported message content format, with the issue potentially coming from Content-Type, Content-Encoding, or inspection of the body itself, not from a server crash (MDN on HTTP 415).
A practical way to think about it is language mismatch. The client sends data in one language, say JSON, XML, or form data. The server expects a different one, or the request claims one language in headers while speaking another in the body.

Three headers usually matter most:
Content-Typetells the server what the body format is, such asapplication/json,application/xml, ormultipart/form-data.Content-Encodingtells the server whether the body was transformed before transit, such as withgzip.Accepttells the server what response format the client wants back. That one matters more for response negotiation than for 415 itself.
Practical rule: If the header says JSON, send valid JSON. If the body is compressed, declare the encoding accurately. If you're unsure, capture the exact wire request instead of trusting what the client code intended to send.
This is why 415 often appears early in integrations. The server rejects the request before business logic runs. In incident terms, that's good news. You usually don't need to chase database behavior, thread pools, or downstream latency. You need to inspect the request contract.
If you're also seeing response negotiation issues, compare this problem with HTTP 406 troubleshooting. The two errors get confused often, but they fail on different sides of the exchange.
Diagnosing Client-Side Causes and Fixes
Most 415 incidents start on the sending side. A frontend, mobile app, script, test runner, or API client says it's sending one format while sending another, or it omits a required header entirely.

Start with the raw request
Don't debug this from application code first. Reproduce it with curl, because curl removes browser abstractions and most client-library surprises.
A failing example often looks like this:
curl -X POST https://api.example.test/orders \
-H "Content-Type: text/plain" \
-d '{"id":"123","status":"paid"}'
That body is JSON, but the header says plain text.
The corrected request is straightforward:
curl -X POST https://api.example.test/orders \
-H "Content-Type: application/json" \
-d '{"id":"123","status":"paid"}'
Use the same method, same body, same endpoint, then change only the header. If the second request works, you've isolated the cause. If it still fails, compare the body bytes next. A surprisingly common failure is malformed JSON pasted from logs, templates, or test fixtures.
A short audit checklist helps:
- Match header to body. JSON body means
application/json. - Check for accidental charset additions. Some servers reject forms like
application/json; charset=utf8, while others accept them. - Verify the method. Some APIs only accept a given media type on
POSTorPUT, not on a redirected or retried request. - Look for client defaults. Postman, Axios, and wrapper SDKs may overwrite headers based on body type.
Check browser behavior before blaming the API
Browser requests add another failure mode that doesn't show up in curl. The overlooked CORS interaction is that when no-cors mode is used, browsers force Content-Type to text/plain, which can trigger 415 on JSON endpoints (Stack Overflow discussion of the no-cors and text/plain fallback).
That means code like this can fail even though the body is serialized correctly:
fetch("/api/orders", {
method: "POST",
mode: "no-cors",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ id: "123", status: "paid" })
})
In practice, the browser may not send the header you think it does.
When a browser is involved, trust DevTools over source code. The request that left the tab is the one that matters.
Use fetch like this instead:
fetch("/api/orders", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ id: "123", status: "paid" })
})
If CORS is blocking the request, fix CORS on the server. Don't hide it with no-cors, because that usually creates a second problem and makes debugging harder.
Later in the investigation, it helps to watch a walkthrough of common request mistakes before you diff packets and logs:
Fixing Common Server-Side Configuration Issues
Sometimes the client is correct and the server is the one enforcing a narrower contract than the team realizes. In those cases, error code 415 means the route, parser, or framework configuration won't consume what the client sent.

Baeldung notes that HTTP 415 is defined in RFC 7231 Section 6.5.13 and commonly happens when the payload media type doesn't match what the target resource supports, such as sending JSON while declaring text/plain to a JSON-only endpoint (Baeldung on Spring 415 behavior).
When the route only accepts one media type
Frameworks often let you declare accepted media types per endpoint. That's useful for safety, but strict declarations can surprise teams during migrations.
In Spring Boot, a route may be limited like this:
@PostMapping(
path = "/orders",
consumes = "application/json"
)
public ResponseEntity<?> createOrder(@RequestBody OrderRequest request) {
return ResponseEntity.ok().build();
}
If a client sends application/xml or text/plain, Spring can reject it before the controller body runs.
A similar trap appears when an older endpoint originally accepted form submissions and a new client starts sending JSON. The body may be valid, the authentication may pass, and logging may still show only a 415 because the framework stopped the request before your business code executed.
Middleware and parser gaps
Node.js and Express fail differently. The route may exist, but without a body parser the app can't parse the incoming format the way the handler expects.
For JSON, the usual baseline is:
const express = require("express");
const app = express();
app.use(express.json());
app.post("/orders", (req, res) => {
res.json({ received: req.body });
});
Without express.json(), you can end up with an empty or unusable body, or custom middleware may reject the request based on header checks before parsing happens.
Check these server-side points in order:
| Server check | What to inspect | Typical fix |
|---|---|---|
| Route media restrictions | consumes, content negotiation settings, request mapping |
Add the correct media type or update the client |
| Body parsing middleware | JSON, XML, form-data parsers | Enable the parser before route handlers |
| Reverse proxy rewrites | Header normalization or stripping | Preserve request headers through the proxy |
| Upload handlers | Multipart expectations | Use multipart/form-data when files are involved |
Server-side 415 handling should be explicit. If a route only accepts JSON, say so in code, document it, and return a clear error body instead of a bare status line.
Troubleshooting Advanced Scenarios with Encoding and Proxies
The hardest 415 incidents are the ones where Content-Type is correct, the payload validates, and the endpoint still refuses the message. That's where Content-Encoding and intermediate components matter.
Content-Encoding is not the same as Content-Type
Content-Type describes the media format. Content-Encoding describes how that body was encoded for transport. A request can be JSON and still be unreadable to the server if the client says it's compressed with an encoding the server doesn't support.
Apigee's troubleshooting guidance is useful here because it highlights a missed point in many runbooks. RFC 7231 ties 415 not only to unsupported media types but also to unsupported encoding values, and Apigee Edge can surface 415 faults when backend responses declare unsupported encodings such as br for Brotli (Apigee on unsupported encoding and 415 faults).
That distinction changes the fix. If the problem is encoding, changing application/json won't help.
What proxies and gateways change
In distributed systems, the failing component might not be the original client or the final backend. A gateway can decompress, recompress, preserve, or reject headers along the path.
Look at the chain this way:
- Client to gateway. The client may send compressed content the gateway doesn't support.
- Gateway to backend. The gateway may forward a header without transforming the body correctly.
- Backend to gateway. The backend may respond with an encoding that the gateway can't process.
- Observability layer. Logs at one hop may show only a generic 415 unless headers are captured.
Per-hop logging becomes essential. If you only inspect application logs, you might miss that the rejection happened at the edge tier. Strong microservices logging practices help because they let you compare ingress, proxy, and app-layer events for the same request path.
A quick field checklist for advanced 415s:
- Inspect
Content-Encodingdirectly. Don't assume it's absent. - Check whether a proxy modifies compression settings.
- Compare headers at each hop rather than relying on a single log source.
- Test without compression to see if the status changes.
If
Content-Typelooks right and 415 persists, stop reformatting JSON. Inspect compression and the path through your proxies.
Detecting and Triaging 415 Errors with Log Management
A 415 is usually easy to explain once you see the request. The hard part in production is finding the exact failing combination of endpoint, client, and header set before the incident spreads.
Reliqus describes HTTP 415 as an early-stage integration error that appears when the server inspects the message body and finds a format it doesn't support, typically due to mismatch between the declared Content-Type and the actual data sent (Reliqus guide to HTTP 415 causes). That's why log triage matters. You want to catch the mismatch near ingress, before the rest of the stack gets pulled into the incident.

What to look for in raw logs
Start with access logs. In Nginx or Apache style logs, isolate requests returning 415 and line them up by endpoint and user agent. You're looking for patterns, not single events.
The useful fields are:
- Status code to confirm 415 and separate it from 400 or 422 noise
- Method and path to identify whether one route is enforcing stricter media rules
- User-Agent or client name to find one broken SDK or browser flow
- Request length to distinguish empty-body mistakes from full payload mismatches
- Correlated request ID if your stack emits one
If your logs include structured request metadata, inspect content_type and content_encoding side by side. That pairing shortens the investigation dramatically.
How to narrow the blast radius fast
Centralized logs make this less manual. A practical search might look like status:415 stream:api-gateway, then narrow by endpoint, host, deployment version, or client identifier.
That gives you a sequence:
- Find all 415s in the affected window.
- Group by route to see whether one endpoint owns the incident.
- Group by caller to identify a single frontend build, batch job, or SDK version.
- Jump to application logs for the same request IDs and confirm whether the request reached the handler at all.
The first question isn't “why did this body fail.” It's “which exact clients started failing, on which routes, after what change.”
For ongoing operations, it helps to keep search patterns and routing clean. That's one reason teams adopt centralized log design principles such as log management best practices for structured triage.
If you're using an MCP-compatible AI client, chat-based queries are useful during incidents. Asking for “all 415 errors in the last hour for the gateway stream” is often faster than rebuilding the same filters by hand while a deploy rollback is already under discussion.
Proactive Prevention and Alerting Strategies
The cheapest 415 is the one that never reaches production. Teams prevent most of them by making accepted media types impossible to misunderstand.
Prevent the mismatch before runtime
Document the request contract precisely. If an endpoint accepts JSON only, say application/json. If a file upload requires multipart/form-data, say that too. Ambiguity invites client defaults, and client defaults are where 415 incidents start.
Contract testing helps because it catches drift between producer and consumer before rollout. Typed client generation helps for the same reason. When the client library serializes the body and sets headers consistently, developers have fewer chances to send the wrong format by hand.
A practical prevention stack looks like this:
- Explicit API schemas in OpenAPI or similar specs
- Contract tests in CI to validate media types and request shapes
- Generated clients for common consumers instead of handwritten wrappers
- Pre-release smoke tests using real HTTP requests, not only unit tests
Alert on patterns, not noise
Alert on a spike or sustained cluster of 415s per service or endpoint. One isolated 415 may be a bad request from a single user. A burst after a deployment usually means a bad client build, a changed route contract, or a proxy-level header issue.
Useful alerts usually key off:
- Service or route
- Deployment window
- Client identifier if available
- Error concentration over time rather than single events
That approach wakes the on-call team for an actual integration break, not for every malformed test request that hits the edge.
Frequently Asked Questions About HTTP 415
Is 415 the same as 400
No. A 400 Bad Request usually points to malformed syntax or a structurally invalid request. A 415 Unsupported Media Type points to a format mismatch between what the client sent and what the server is willing to accept.
A useful shorthand is this: 400 often means “I can read this request, but it's wrong.” 415 means “I won't process this body in this format.”
Can a GET request return 415
It can, but it's less common because GET requests usually don't send request bodies. You'll see it in edge cases involving unusual clients, redirects, proxy behavior, or APIs that inspect headers and reject an unexpected body or encoding on a GET-like flow.
When a GET unexpectedly shows 415, inspect intermediaries first. A gateway or client library may have changed the request shape before it reached the backend.
Why file uploads often trigger 415
File upload handlers usually expect multipart/form-data. If the client posts raw JSON metadata while trying to include a file, or manually sets the wrong Content-Type, the server can reject the request before upload processing begins.
In browsers, let the runtime build the multipart boundary when using FormData. Manually hardcoding that header is a common way to break an otherwise valid upload.
If your team needs faster incident triage around request failures like error code 415, Fluxtail gives you centralized logs, live tail, clear stream routing, and MCP-ready chat queries so you can go from “the API is failing” to the exact endpoint, host, and header pattern without bouncing between tools.