Content-Type Header Errors: How to Debug 415 Unsupported Media Type
A 415 Unsupported Media Type is one of those errors that looks like it should be simple to fix — the name tells you exactly what’s wrong. But in practice, it’s often unclear why the Content-Type you’re sending isn’t matching what the server expects, especially when you’re not the one writing the request.
This guide covers how Content-Type works, the most common ways it breaks, and how to debug it by injecting and testing different Content-Type values directly in Chrome using HeaderSnap — without modifying your application code.
What the Content-Type Header Does
Content-Type tells the server what format the request body is in. The server uses this information to parse the body correctly. If the header doesn’t match the actual body format — or doesn’t match what the server accepts — the server rejects the request.
The Content-Type header appears on requests with a body: POST, PUT, PATCH. GET requests typically don’t include it.
Common Content-Type values:
| Value | Used for |
|---|---|
application/json | JSON body (REST APIs, most modern APIs) |
application/x-www-form-urlencoded | HTML form data, key=value pairs |
multipart/form-data | File uploads, forms with binary content |
text/plain | Plain text body |
application/xml | XML payloads (older SOAP APIs) |
The Two Common Errors
415 Unsupported Media Type
The server received your request but doesn’t accept the Content-Type you specified (or didn’t specify).
HTTP/1.1 415 Unsupported Media Type
{"error": "Content type 'text/plain' not supported"}
Usually means: the Content-Type header is wrong, absent, or in a format the server hasn’t been configured to handle.
400 Bad Request (Content-Type related)
The server accepted the Content-Type but couldn’t parse the body because the actual content doesn’t match.
HTTP/1.1 400 Bad Request
{"error": "Invalid JSON payload"}
Usually means: the Content-Type says application/json but the body is malformed JSON, or it says application/x-www-form-urlencoded but the body is raw JSON.
Why This Happens in Practice
From frontend code: fetch() doesn’t automatically set Content-Type when you pass a body. If you’re sending a JSON string without explicitly setting the header, the browser may send text/plain or omit the header entirely.
// Missing Content-Type — server may return 415
fetch('/api/submit', {
method: 'POST',
body: JSON.stringify(data),
});
// Correct
fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
From form submissions: HTML forms default to application/x-www-form-urlencoded. If the server expects JSON and you’re submitting a form directly, the Content-Type won’t match.
From third-party SDKs or libraries: Sometimes the library sets a Content-Type you don’t expect, and it conflicts with what the API requires.
Debugging With Header Injection
The fastest way to debug a 415 is to override the Content-Type header and test different values until the server responds correctly. Once you know the working value, you can fix it in your code.
Step 1: Identify what Content-Type your request is currently sending
Open Chrome DevTools → Network tab → find the failing request → click it → go to Headers → look at the Request Headers section. Note the value of Content-Type (or confirm it’s missing).
Step 2: Set up a Content-Type override rule in HeaderSnap
- Open HeaderSnap → Rules tab → Add Rule
- Name it:
Debug Content-Type - URL Pattern: match your endpoint (e.g.,
*api.yourapp.com/submit*) - Header Target: Request
- Action: Set
- Header Name:
Content-Type - Header Value:
application/json(start with this, then iterate)
Step 3: Trigger the request and check the response
Reload the page or re-trigger the action that sends the request. Check the Network tab — if the 415 is gone, you’ve found the right Content-Type. If not, go back to HeaderSnap and try a different value.
Values to test in order:
application/jsonapplication/x-www-form-urlencodedmultipart/form-data(for file uploads)application/json; charset=utf-8(some servers require the charset)
Real-World Scenarios
Scenario: REST API call returning 415
You’re calling a third-party REST API from a frontend fetch call. The 415 appears in the console. DevTools shows Content-Type: text/plain;charset=UTF-8 on the request — the browser set it automatically because you passed a string body without specifying the header.
Fix: Add a HeaderSnap rule to set Content-Type: application/json on that URL pattern, confirm the 415 is gone, then add headers: { 'Content-Type': 'application/json' } to your fetch call and remove the rule.
Scenario: File upload returning 400
You’re uploading a file with a <input type="file"> and the backend returns 400. DevTools shows Content-Type: application/json on the request — a previous rule or library override is setting the wrong type for a file upload.
Fix: Use HeaderSnap to remove the Content-Type header entirely for that endpoint. For multipart/form-data with file uploads, the browser must set Content-Type automatically (with the boundary parameter included). Overriding it manually breaks the upload.
Create a “Remove” action rule instead of a “Set” action:
- Action: Remove
- Header Name:
Content-Type
The browser will then set the correct multipart/form-data; boundary=... automatically.
Scenario: Form submission hitting a JSON-only API
Your app has a legacy HTML form submitting to an API endpoint that only accepts application/json. The form submission sets application/x-www-form-urlencoded and the server returns 415.
You can test whether the API accepts application/x-www-form-urlencoded by setting a HeaderSnap rule — but if it doesn’t, the fix is to stop using a direct form submission and switch to a JavaScript fetch call with the correct Content-Type and a serialized JSON body.
Quick Reference
| Situation | Content-Type to use |
|---|---|
| JSON API call (REST) | application/json |
| HTML form without files | application/x-www-form-urlencoded |
| Form with file uploads | Let the browser set it (don’t override) |
| Raw text body | text/plain |
The debug workflow is always the same: check what Content-Type is currently being sent, override it with HeaderSnap, iterate until the server accepts it, then fix the source code.
HeaderSnap is free with no telemetry.