CloudFlare returns 415 Error on HTTP/2 API call

Or why Accept headers mattered more than it seemed

Recently, while debugging a seemingly simple API call made with JavaScript’s fetch() function, I encountered an issue that led me down a rabbit hole of HTTP protocol differences, CloudFlare behavior, and header validation strictness. What started as a “works in Postman, fails in my app” scenario turned into a discovery about how HTTP/2 and HTTP/1.1 are handled differently by CloudFlare and still remains a mistery why it happened.

The Problem

The issue manifested as a CloudFlare-generated 415 Unsupported Media Type error when making API calls from a mobile application, while the identical request worked perfectly through Postman (web based). Here’s the JavaScript code that was failing:

await fetch(API.login, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    username: email,
    password: password,
  }),
});

The response headers clearly showed CloudFlare was intercepting the request:

Content-Type: text/html
Server: cloudflare

Instead of reaching the backend API, CloudFlare was returning an HTML error page with “415 Unsupported Media Type.”

The Investigation: Isolating Variables

Through systematic testing, I discovered the key difference: HTTP protocol version.

  • Postman (working): HTTP/1.1
  • Mobile app (failing): HTTP/2

When I configured Postman to use HTTP/2, it immediately started producing the same 415 error. This confirmed that the protocol version was the culprit, not the request content itself.

The Root Cause: “Accept” Header Validation

The breakthrough came through methodical header elimination in Postman’s HTTP/2 mode. By disabling default headers one by one, I discovered that the Accept header was the problematic element.

The failing scenario:

Accept: */*  (Postman's default)

The working solution:

Accept: application/json

Why This Happens?

The research reveals that this isn’t necessarily a bug, but rather a consequence of how different systems handle HTTP/2 requests compared to HTTP/1.1. To be honest I haven’t found anywhere a single documentation that says that Accept header need to be used with specific values and not the wild card for HTTP/2 protocols. This could be some security setting coming from CloudFlare that I wasn’t awear of, or just how the CloudFlare is configured. I didn’t found any explicit documentation that has this as a rule for the usage of the Accept header and the RFC 7231 documentation doesn’t have anything on that topic.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.