elastic/elasticsearch · error · IllegalArgumentException

invalid media-type [{}]

Error message

invalid media-type [{}]

What it means

Thrown by ParsedMediaType.parseMediaType() when the media type string does not conform to the RFC 7231 token/token structure. The method splits on '/', verifies exactly two segments, and checks both against TCHAR_PATTERN (RFC 7230 token characters). If either check fails, the media type is structurally invalid and cannot be parsed.

Source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/ParsedMediaType.java:72

     * but allows only single media type. Media ranges will be ignored (treated as not provided)
     * Note: parsing can return null, but it will throw exceptions once https://github.com/elastic/elasticsearch/issues/63080 is done
     * TODO Do not rely on nulls
     *
     * @return a {@link ParsedMediaType} if the header could be parsed.
     * @throws IllegalArgumentException if the header is malformed
     */
    public static ParsedMediaType parseMediaType(String headerValue) {
        if (headerValue != null) {
            if (isMediaRange(headerValue) || "*/*".equals(headerValue)) {
                return null;
            }
            final String[] elements = headerValue.toLowerCase(Locale.ROOT).split(";");

            final String[] splitMediaType = elements[0].split("/");
            if ((splitMediaType.length == 2
                && TCHAR_PATTERN.matcher(splitMediaType[0].trim()).matches()
                && TCHAR_PATTERN.matcher(splitMediaType[1].trim()).matches()) == false) {
                throw new IllegalArgumentException("invalid media-type [" + headerValue + "]");
            }
            if (elements.length == 1) {
                return new ParsedMediaType(headerValue, splitMediaType[0].trim(), splitMediaType[1].trim(), new HashMap<>());
            } else {
                Map<String, String> parameters = new HashMap<>();
                for (int i = 1; i < elements.length; i++) {
                    String paramsAsString = elements[i].trim();
                    if (paramsAsString.isEmpty()) {
                        continue;
                    }
                    // spaces are allowed between parameters, but not between '=' sign
                    String[] keyValueParam = paramsAsString.split("=");
                    if (keyValueParam.length != 2 || hasTrailingSpace(keyValueParam[0]) || hasLeadingSpace(keyValueParam[1])) {
                        throw new IllegalArgumentException("invalid parameters for header [" + headerValue + "]");
                    }
                    String parameterName = keyValueParam[0].toLowerCase(Locale.ROOT).trim();
                    String parameterValue = keyValueParam[1].toLowerCase(Locale.ROOT).trim();
                    parameters.put(parameterName, parameterValue);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Correct the header to use the standard 'type/subtype' format (e.g., 'application/json').
  2. Ensure there are no stray characters, extra slashes, or missing segments.
  3. Validate the header value with an HTTP client that enforces correct Content-Type formatting.
  4. Check intermediary proxies/gateways for header corruption.

Example fix

// before
Content-Type: application

// after
Content-Type: application/json
Defensive patterns

Strategy: validation

Validate before calling

// Validate media type format before parsing
private static final Pattern MEDIA_TYPE = Pattern.compile("^[a-zA-Z0-9!#$&.+\-^_]+/[a-zA-Z0-9!#$&.+\-^_]+$");
public static void validateMediaType(String header) {
    if (!MEDIA_TYPE.matcher(header.split(";")[0].trim()).matches()) {
        throw new IllegalArgumentException("Invalid media type: " + header);
    }
}

Try / catch

try {
    ParsedMediaType parsed = ParsedMediaType.parseMediaType(header);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("invalid media-type")) {
        return ResponseEntity.status(415).body("Unsupported Media Type");
    }
    throw e;
}

Prevention

When it happens

Trigger: Sending an Accept or Content-Type header with a value like 'application' (missing subtype), 'application/' (empty subtype), '/json' (empty type), 'application/json/xml' (three segments), or containing characters outside the TCHAR set such as spaces or control characters in the type/subtype portions.

Common situations: Typo in a Content-Type header value. Custom HTTP client sending a malformed header. Intermediary proxy stripping or corrupting the Content-Type. Sending a vendor-specific media type with invalid characters.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/3700397ec2bcc5cb. Report an issue: GitHub.