{"record":{"id":"694cab1482a90ad9","repo":"quarkusio/quarkus","slug":"needs-a-boundary-value","errorCode":null,"errorMessage":"Needs a boundary value","messagePattern":"Needs a boundary value","errorType":"exception","errorClass":"ErrorDataDecoderException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusHttpPostBodyUtil.java","lineNumber":300,"sourceCode":"        // Check if Post using \"multipart/form-data; boundary=--89421926422648 [; charset=xxx]\"\n        String[] headerContentType = splitHeaderContentType(contentType);\n        final String multiPartHeader = HttpHeaderValues.MULTIPART_FORM_DATA.toString();\n        if (headerContentType[0].regionMatches(true, 0, multiPartHeader, 0, multiPartHeader.length())) {\n            int mrank;\n            int crank;\n            final String boundaryHeader = HttpHeaderValues.BOUNDARY.toString();\n            if (headerContentType[1].regionMatches(true, 0, boundaryHeader, 0, boundaryHeader.length())) {\n                mrank = 1;\n                crank = 2;\n            } else if (headerContentType[2].regionMatches(true, 0, boundaryHeader, 0, boundaryHeader.length())) {\n                mrank = 2;\n                crank = 1;\n            } else {\n                return null;\n            }\n            String boundary = StringUtil.substringAfter(headerContentType[mrank], '=');\n            if (boundary == null) {\n                throw new HttpPostRequestDecoder.ErrorDataDecoderException(\"Needs a boundary value\");\n            }\n            if (boundary.charAt(0) == '\"') {\n                String bound = boundary.trim();\n                int index = bound.length() - 1;\n                if (bound.charAt(index) == '\"') {\n                    boundary = bound.substring(1, index);\n                }\n            }\n            final String charsetHeader = HttpHeaderValues.CHARSET.toString();\n            if (headerContentType[crank].regionMatches(true, 0, charsetHeader, 0, charsetHeader.length())) {\n                String charset = StringUtil.substringAfter(headerContentType[crank], '=');\n                if (charset != null) {\n                    return new String[] { \"--\" + boundary, charset };\n                }\n            }\n            return new String[] { \"--\" + boundary };\n        }\n        return null;","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusHttpPostBodyUtil.java#L282-L318","documentation":"QuarkusHttpPostBodyUtil.getMultipartDataBoundary parses the multipart Content-Type header to extract the boundary parameter. When the header contains a 'boundary=' token but the substring after '=' is null or absent, it throws HttpPostRequestDecoder.ErrorDataDecoderException with this message. The client cannot frame multipart body parts without a boundary string, so decoding fails fast.","triggerScenarios":"Sending a multipart request whose Content-Type header declares a boundary attribute incorrectly, e.g. 'multipart/form-data' with no '=' after boundary, or a manually set header like 'Content-Type: multipart/form-data; boundary' (missing value).","commonSituations":"Manually constructing the multipart Content-Type header instead of letting the client generate it; copying a header from a tool (curl, Postman) and dropping the boundary value; proxy layers that strip header values.","solutions":["Do not set the multipart Content-Type header manually; let the REST Client set it including a generated boundary","If setting it manually, include a non-empty value: Content-Type: multipart/form-data; boundary=<token>","Inspect the outgoing Content-Type header for a truncated boundary value (e.g. missing text after '=')","Ensure no middleware/proxy rewrites or truncates the Content-Type header"],"exampleFix":"// before\nrequest.header(\"Content-Type\", \"multipart/form-data; boundary\");\n// after\n// remove the manual header; the multipart encoder sets it:\n// Content-Type: multipart/form-data; boundary=XXXX","handlingStrategy":"validation","validationCode":"String ct = requestContentType; // e.g. header value\nif (ct != null && ct.toLowerCase().startsWith(\"multipart/\")) {\n    int i = ct.indexOf(\"boundary=\");\n    if (i < 0 || ct.substring(i + \"boundary=\".length()).isBlank()) {\n        throw new IllegalStateException(\"multipart Content-Type must include a boundary value\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return client.multipartCall(...);\n} catch (jakarta.ws.rs.ProcessingException e) {\n    if (e.getCause() instanceof HttpPostRequestDecoder.ErrorDataDecoderException) {\n        throw new IllegalStateException(\"Fix the multipart Content-Type: boundary value missing\", e);\n    }\n    throw e;\n}","preventionTips":["Never set Content-Type manually for multipart calls; let the client generate the boundary","If a header must be preset, always include boundary=<token>","Log the outgoing Content-Type when debugging multipart failures"],"tags":["http","multipart","client","request-parsing"],"backgroundTag":"missing-multipart-boundary","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}