{"record":{"id":"6f2df16e3cd2614f","repo":"OpenFeign/feign","slug":"multipart-body-could-not-be-read","errorCode":null,"errorMessage":"Multipart body could not be read.","messagePattern":"Multipart body could not be read\\.","errorType":"exception","errorClass":"HttpMessageNotReadableException","httpStatus":null,"severity":"error","filePath":"form-spring/src/main/java/feign/form/spring/converter/SpringManyMultipartFilesReader.java","lineNumber":109,"sourceCode":"\n    MediaType contentType = headers.getContentType();\n    if (contentType == null) {\n      throw new HttpMessageNotReadableException(\"Content-Type is missing.\", inputMessage);\n    }\n\n    val boundaryBytes = getMultiPartBoundary(contentType);\n    MultipartStream multipartStream =\n        new MultipartStream(inputMessage.getBody(), boundaryBytes, bufSize, null);\n\n    val multiparts = new LinkedList<ByteArrayMultipartFile>();\n    for (boolean nextPart = multipartStream.skipPreamble();\n        nextPart;\n        nextPart = multipartStream.readBoundary()) {\n      ByteArrayMultipartFile multiPart;\n      try {\n        multiPart = readMultiPart(multipartStream);\n      } catch (Exception e) {\n        throw new HttpMessageNotReadableException(\n            \"Multipart body could not be read.\", e, inputMessage);\n      }\n      multiparts.add(multiPart);\n    }\n    return multiparts.toArray(new ByteArrayMultipartFile[0]);\n  }\n\n  @Override\n  protected void writeInternal(\n      MultipartFile[] byteArrayMultipartFiles, HttpOutputMessage outputMessage) {\n    throw new UnsupportedOperationException(\n        getClass().getSimpleName() + \" does not support writing to HTTP body.\");\n  }\n\n  private byte[] getMultiPartBoundary(MediaType contentType) {\n    val boundaryString = unquote(contentType.getParameter(\"boundary\"));\n    if (StringUtils.hasLength(boundaryString) == false) {\n      throw new HttpMessageConversionException(\"Content-Type missing boundary information.\");","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/form-spring/src/main/java/feign/form/spring/converter/SpringManyMultipartFilesReader.java#L91-L127","documentation":"SpringManyMultipartFilesReader is a Spring HttpMessageConverter that parses a multipart/mixed request body into an array of ByteArrayMultipartFile. When reading any part of the multipart stream fails (malformed boundary, truncated body, I/O error), it wraps the cause in Spring's HttpMessageNotReadableException to signal the request body is unreadable.","triggerScenarios":"Calling readInternal on a request whose multipart body is malformed: wrong or missing boundary parameter, truncated stream, or readMultiPart throwing (e.g. bad Content-Disposition headers or an IOException from MultipartStream).","commonSituations":"A Feign/proxy client posts multipart data to a Spring controller endpoint that decodes with this converter; the client encodes with a different boundary convention, a gateway truncates the body, or the Content-Type boundary was altered in transit.","solutions":["Verify the client's Content-Type header is multipart/form-data with a boundary parameter matching the body's delimiters","Compare the raw request body (e.g. via a logging filter) against the RFC 2046 multipart format the client produced","Check for proxies/load balancers that truncate or re-encode request bodies","If a custom encoder produced the body, ensure it writes proper CRLF-delimited boundary lines"],"exampleFix":"// before: client sends Content-Type: multipart/form-data (no boundary)\nheader(\"Content-Type\", \"multipart/form-data\");\n// after: let the form encoder set the boundary\nheader(\"Content-Type\", \"multipart/form-data; boundary=\" + boundary);","handlingStrategy":"try-catch","validationCode":"String ct = request.getHeaders().getFirst(\"Content-Type\");\nif (ct == null || !ct.contains(\"boundary=\")) {\n  throw new IllegalArgumentException(\"multipart Content-Type must carry a boundary\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  MultipartFile[] parts = converter.read(type, context);\n} catch (HttpMessageNotReadableException e) {\n  logger.warn(\"malformed multipart body\", e.getCause());\n  throw new ResponseStatusException(HttpStatus.BAD_REQUEST, \"malformed multipart body\", e);\n}","preventionTips":["Always send multipart bodies via an encoder that sets the boundary itself","Log raw bodies in dev to catch malformed multipart payloads early","Test against proxies/gateways that may alter or truncate bodies"],"tags":["spring","multipart","http-message-conversion","request-body"],"backgroundTag":"invalid-json-response","analyzedSha":"e2a1e27560a1e68840c34f031afca88b36096e30","analyzedAt":"2026-09-10T12:37:37.238Z","contentChangedAt":"2026-09-10T12:37:37.238Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}