Fluxtail
Log Management Guides

Error Code 415: How to Fix Unsupported Media Type

Learn what HTTP 415 means and fix Content-Type, Content-Encoding, JSON, multipart, CORS, redirect, gateway, and parser mismatches safely.

By Fluxtail Engineering Updated

HTTP error code 415 Unsupported Media Type means the origin server refuses a request because its content format is not supported for that HTTP method and resource. The mismatch can involve the declared Content-Type, the request's Content-Encoding, or the bytes the server actually inspects.

That definition comes from RFC 9110, section 15.5.16. MDN's practical 415 reference describes the same causes. A 415 response usually points to the request representation rather than the URL itself: the client and endpoint disagree about what was sent or how to decode it.

What error code 415 means

Three values need to agree:

  1. The endpoint contract must allow the media type for this method and path.
  2. Content-Type must describe the body accurately.
  3. Any Content-Encoding must describe an encoding the receiver can decode.

For example, an endpoint may accept JSON for POST /v1/orders but reject XML, form data, or gzip-compressed JSON. It may also reject a body that claims to be JSON but begins with binary data. The server can return the same 415 status for each of those conditions.

Content-Type identifies the representation's media type. Content-Encoding identifies transformations, such as gzip compression, that must be reversed before interpreting that media type. RFC 9110 defines these fields separately, and confusing them leads to fixes that change the wrong header.

Check these facts before changing code

Capture a small, safe evidence set from the failing exchange:

  • exact HTTP method and path, excluding credentials and sensitive query values;
  • response status and a request or correlation ID;
  • request Content-Type and Content-Encoding;
  • response Accept or Accept-Encoding, if the server supplies them;
  • body size and, when needed, a hash or bounded sanitized sample;
  • client name and version;
  • time in UTC and the deployment or release serving the route.

Do not save authorization headers, cookies, tokens, multipart file contents, or complete customer payloads. A digest can prove that two hops saw the same bytes without storing the body itself.

Evidence Likely next check
Missing or wrong Content-Type Compare the client serializer and endpoint's accepted request media types
Correct type, unsupported Content-Encoding Remove the coding for one controlled test or enable a supported decoder
Header says JSON, inspected bytes are not JSON Check serialization, double encoding, and proxy transformations
Only one API version or route fails Compare that route's parser and media-type contract
Edge logs 415 but application has no request Inspect gateway, WAF, upload, and decompression rules
Application logs a parser or route rejection Inspect middleware order and handler media-type restrictions
Browser fails but the same request works outside the browser Separate the actual HTTP response from CORS enforcement and preflight behavior
Failure begins with one client release Compare its body encoder, headers, redirect handling, and compression settings

The emitting component matters. A CDN, API gateway, reverse proxy, framework middleware, or application handler can generate a 415. Correlate the same request ID across available hops; an absent application event often means the request was rejected earlier.

Send JSON with the correct media type

This curl request sends an original, minimal JSON document and declares it as JSON:

curl --fail-with-body \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{"order_id":"ord_example_1042","quantity":1}' \
  'https://api.example.com/v1/orders'

Use a non-production endpoint or an idempotency mechanism before reproducing a request that creates, charges, deletes, or otherwise changes state. Replaying a failed write can duplicate the operation if the original server completed it before returning an error.

With curl 7.82.0 or later, the shorter --json option sends the supplied argument through --data-binary and adds Content-Type: application/json plus Accept: application/json:

curl --fail-with-body \
  --json '{"order_id":"ord_example_1042","quantity":1}' \
  'https://api.example.com/v1/orders'

These examples prove only what the client sends. Curl does not validate that the --json argument is valid JSON. The endpoint still has to allow application/json, and the document must satisfy its syntax and schema requirements. See curl's current --json documentation for the exact shortcut behavior.

JSON syntax errors are usually not 415

If an endpoint supports application/json but receives malformed JSON, the media type is supported and the document is invalid. A 400 Bad Request is normally more accurate than 415. If the JSON is well formed and the media type is understood but its instructions cannot be processed, 422 Unprocessable Content may be more accurate.

Do not change a 415 into a 500 merely to make a client library continue. Status codes should preserve the failure boundary so logs, alerts, and clients can respond correctly.

Send multipart data without writing the boundary yourself

For a file-upload route that accepts multipart/form-data, let the client generate the boundary and matching body framing:

curl --fail-with-body \
  --form 'document=@./invoice.pdf;type=application/pdf' \
  --form 'reference=inv_example_8472' \
  'https://api.example.com/v1/documents'

Do not add Content-Type: multipart/form-data manually. The header requires a boundary parameter that must match the separators in the encoded body. curl --form creates both together; overriding only the header can produce a body the server cannot parse.

A multipart request is not interchangeable with application/x-www-form-urlencoded. URL-encoded form data represents name-value fields, while multipart supports independently described parts and file content. Send the format the route documents.

Match the route's actual media-type contract

A correct request is not always JSON. Common request representations include:

  • application/x-www-form-urlencoded for conventional form fields;
  • multipart/form-data for forms containing files or independently typed parts;
  • application/xml for an XML contract;
  • application/octet-stream for uninterpreted binary content;
  • a vendor media type such as application/vnd.example.order+json for a versioned JSON-based contract.

The +json suffix indicates JSON-based structured syntax, but it does not force every endpoint that accepts application/json to accept every vendor subtype. Likewise, parameters such as charset can be part of an endpoint or framework's matching rules. Compare the exact media type and parameters against the published API or OpenAPI document instead of guessing.

Add contract tests for every accepted request type. A useful test matrix includes the supported type, a missing type, an unsupported type, malformed content of a supported type, and any supported content coding. Verify both the status and the response guidance.

Do not confuse request and response negotiation

The similarly named headers describe different directions:

Header What it describes
Request Content-Type Media type of the request body being sent
Request Content-Encoding Coding applied to the request body, such as gzip
Request Accept Response media types the client can use
Request Accept-Encoding Content codings the client can decode in the response

Accept does not repair an incorrect request Content-Type. It expresses a preference for the response. When an origin rejects the request media type with 415, RFC 9110 says it can include Accept in the response to indicate media types accepted in a later request. When it rejects the request coding, it ought to use response Accept-Encoding to identify acceptable codings.

RFC 9110 does not require Accept-Post in a 415 response. Clients should not assume every 415 includes that field, Accept, or Accept-Encoding; the API contract remains the authoritative source.

For response negotiation failures, see how HTTP 406 differs from 415.

Choose 415 only for an unsupported request format

Nearby status codes answer different questions:

Status Use it when
400 Bad Request Request syntax, framing, or a supported representation is malformed
406 Not Acceptable The server cannot provide a response representation acceptable under the request's negotiation fields
413 Content Too Large The request content exceeds what the server is willing or able to process
415 Unsupported Media Type The request media type, content coding, or inspected format is unsupported for this method and resource
422 Unprocessable Content The type and syntax are understood, but the contained instructions cannot be processed

These distinctions follow RFC 9110's client-error definitions. Returning 415 for every body validation failure hides whether the client chose the wrong representation, produced invalid syntax, or supplied invalid domain data.

Diagnose a 415 through each HTTP hop

Start with one bounded request whose safety is established, then follow it from ingress to the handler.

1. Confirm the exchange, not an assumption

Record the method, path, status, content headers, size, request ID, client version, and UTC time. Avoid verbose command output when it would print credentials or the body. If the original operation is not safe to repeat, use existing logs or reproduce against an isolated test endpoint with an idempotency key.

2. Identify the component that returned 415

Compare CDN or load-balancer access logs, gateway logs, application access logs, and application parser errors. Response headers can provide clues, but do not trust a Server value alone: proxies can preserve, replace, or remove it.

If the edge records a 415 and the application records nothing for the request ID, inspect edge media-type allowlists, request-size checks, WAF rules, and decompression support. If the application records the request, inspect route matching, parser middleware, and handler declarations.

3. Compare headers with the bytes

A JSON serializer should produce JSON bytes and declare a JSON media type. A gzip encoder should set Content-Encoding: gzip only when the body is actually gzip-coded. Check for double serialization, accidental Base64 wrapping, premature decompression, byte-order marks, and a gateway that changes headers without changing the body.

Use a bounded sanitized sample only when a size and hash cannot answer the question. Production payload capture should be narrowly authorized because bodies can contain credentials, personal data, documents, and payment fields.

4. Inspect redirects and client behavior

Redirect handling can change the effective method or discard a request body, depending on the response status and client. Capture the redirect chain without exposing sensitive locations, then confirm the final request method, content headers, and body behavior. Prefer correcting the canonical API URL rather than relying on ambiguous redirect handling for write requests.

5. Change one variable and verify the contract

Test one justified change: the media type, coding, serializer, route declaration, or proxy rule. Configuration and deployment changes need approval. Preserve the original evidence, then verify the same controlled request and confirm that other supported request types still behave as documented.

For services with several gateways and parsers, microservices logging practices explain how consistent request IDs and structured fields make per-hop comparison possible.

Browser 415 errors and CORS are separate failures

A browser console may show Failed to load resource beside a 415 response, but that text does not identify the media mismatch. Inspect the Network panel for the request method, response status, request Content-Type, preflight request, and available response headers.

Setting Fetch to mode: "no-cors" is not a general fix. According to MDN's Request mode reference, no-cors restricts which methods and headers JavaScript can send, and the response is opaque: application code cannot read its status, headers, or body. It can therefore hide useful evidence without making the API accept the representation.

Fix browser access at the server by returning the correct CORS response headers for the intended origin, method, and request headers. MDN's CORS guide explains how browsers use a preflight request for exchanges that require permission before sending the actual request. A preflight rejection and an application 415 are different events; log and diagnose them separately.

Log enough to diagnose 415 without storing payloads

Use an allowlisted structured event at the component that makes the rejection decision. This is a synthetic example; exact field names depend on the server and collector mapping:

{
  "timestamp": "2026-09-15T18:42:17Z",
  "severity": "WARN",
  "service": "orders-api",
  "route": "/v1/orders",
  "http_method": "POST",
  "http_status": 415,
  "content_type": "text/plain",
  "content_encoding": "identity",
  "body_size": 87,
  "client_version": "web-checkout/6.4.1",
  "release": "orders-api-2026.09.15.2",
  "request_id": "req_example_7f3a",
  "rejection_reason": "unsupported_media_type"
}

Allowlist fields such as route, method, status, media type, content coding, size, client version, release, and request ID. Normalize the route template rather than recording sensitive or high-cardinality path values. Exclude bodies, authorization, cookies, API keys, and arbitrary request headers.

Sanitize untrusted strings before logging them so control characters cannot forge extra lines or fields. Limit access, define retention, and protect the store according to the sensitivity of the metadata it contains.

Alert on a 415 ratio, not a raw count

A useful signal is:

415 ratio = requests returning 415 / all eligible requests

Measure numerator and denominator at the same component and over the same routes, methods, and time window. A gateway's 415 count divided by an application's request count is misleading because rejected requests may never reach the application.

Group or filter by stable dimensions such as route template, service, deployment, and client version. Pair the ratio with a minimum request volume or a separate low-traffic rule so one failure does not create a noisy percentage while a real low-volume integration remains observable.

When an alert fires, compare the first affected client or release with the last known-good interval. Use the HTTP 500 investigation guide when the server instead fails while processing a supported request, or follow the Live Tail incident-response guide for a focused log triage sequence.

Investigate recurring 415 responses in Fluxtail

Fluxtail is a paid, logs-focused service with self-service Starter and Pro plans. After a supported collector sends application, gateway, and edge logs through a configured receiver, those events can be routed into named streams and examined with Live Tail, text search, service and severity filters, labels, and mapped fields. Collector-dependent names such as route, content_type, and client_version must be verified before relying on them as filters.

Keep gateway and application events on compatible request IDs, then search the affected time window and narrow by stream, service, status text, release, or labels that your mapping actually preserves. Configure alerts around the same-boundary ratio used in the runbook rather than treating every 415 event as an incident.

Fluxtail's built-in AI chat and hosted MCP are separate access paths. Hosted MCP uses OAuth with PKCE and binds access to one account; its underlying account permissions still apply. Read raw events before accepting a summary, and review any proposed stream or receiver mutation before approving its short-lived confirmation step.

Create a Fluxtail account when centralized logs would make client-version, route, and release correlations easier to retain and investigate.