{"record":{"id":"3700397ec2bcc5cb","repo":"elastic/elasticsearch","slug":"invalid-media-type","errorCode":null,"errorMessage":"invalid media-type [{}]","messagePattern":"invalid media-type \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/x-content/src/main/java/org/elasticsearch/xcontent/ParsedMediaType.java","lineNumber":72,"sourceCode":"     * but allows only single media type. Media ranges will be ignored (treated as not provided)\n     * Note: parsing can return null, but it will throw exceptions once https://github.com/elastic/elasticsearch/issues/63080 is done\n     * TODO Do not rely on nulls\n     *\n     * @return a {@link ParsedMediaType} if the header could be parsed.\n     * @throws IllegalArgumentException if the header is malformed\n     */\n    public static ParsedMediaType parseMediaType(String headerValue) {\n        if (headerValue != null) {\n            if (isMediaRange(headerValue) || \"*/*\".equals(headerValue)) {\n                return null;\n            }\n            final String[] elements = headerValue.toLowerCase(Locale.ROOT).split(\";\");\n\n            final String[] splitMediaType = elements[0].split(\"/\");\n            if ((splitMediaType.length == 2\n                && TCHAR_PATTERN.matcher(splitMediaType[0].trim()).matches()\n                && TCHAR_PATTERN.matcher(splitMediaType[1].trim()).matches()) == false) {\n                throw new IllegalArgumentException(\"invalid media-type [\" + headerValue + \"]\");\n            }\n            if (elements.length == 1) {\n                return new ParsedMediaType(headerValue, splitMediaType[0].trim(), splitMediaType[1].trim(), new HashMap<>());\n            } else {\n                Map<String, String> parameters = new HashMap<>();\n                for (int i = 1; i < elements.length; i++) {\n                    String paramsAsString = elements[i].trim();\n                    if (paramsAsString.isEmpty()) {\n                        continue;\n                    }\n                    // spaces are allowed between parameters, but not between '=' sign\n                    String[] keyValueParam = paramsAsString.split(\"=\");\n                    if (keyValueParam.length != 2 || hasTrailingSpace(keyValueParam[0]) || hasLeadingSpace(keyValueParam[1])) {\n                        throw new IllegalArgumentException(\"invalid parameters for header [\" + headerValue + \"]\");\n                    }\n                    String parameterName = keyValueParam[0].toLowerCase(Locale.ROOT).trim();\n                    String parameterValue = keyValueParam[1].toLowerCase(Locale.ROOT).trim();\n                    parameters.put(parameterName, parameterValue);","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/x-content/src/main/java/org/elasticsearch/xcontent/ParsedMediaType.java#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Correct the header to use the standard 'type/subtype' format (e.g., 'application/json').","Ensure there are no stray characters, extra slashes, or missing segments.","Validate the header value with an HTTP client that enforces correct Content-Type formatting.","Check intermediary proxies/gateways for header corruption."],"exampleFix":"// before\nContent-Type: application\n\n// after\nContent-Type: application/json","handlingStrategy":"validation","validationCode":"// Validate media type format before parsing\nprivate static final Pattern MEDIA_TYPE = Pattern.compile(\"^[a-zA-Z0-9!#$&.+\\-^_]+/[a-zA-Z0-9!#$&.+\\-^_]+$\");\npublic static void validateMediaType(String header) {\n    if (!MEDIA_TYPE.matcher(header.split(\";\")[0].trim()).matches()) {\n        throw new IllegalArgumentException(\"Invalid media type: \" + header);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    ParsedMediaType parsed = ParsedMediaType.parseMediaType(header);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"invalid media-type\")) {\n        return ResponseEntity.status(415).body(\"Unsupported Media Type\");\n    }\n    throw e;\n}","preventionTips":["Use standard HTTP client libraries that construct valid Content-Type headers automatically.","Validate header format before forwarding requests to the parsing layer.","Never manually construct Content-Type strings without understanding the RFC 7231 grammar."],"tags":["http","xcontent","media-type","header-validation","content-type"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}