hyperledger/fabric · warning
cannot read form from request body
Error message
cannot read form from request body
What it means
After determining the multipart boundary, multipartFormDataBodyToBlock streams the request body through multipart.Reader.ReadForm with a size cap of MaxRequestBodySize (body) and twice that for form memory. If the form cannot be parsed — malformed multipart syntax, truncated body, or body exceeding MaxBytesReader's limit — the handler returns 400 with this wrapped error.
Source
Thrown at orderer/common/channelparticipation/restapi.go:432
h.sendUpdateError(err, resp)
return
}
info.URL = path.Join(URLBaseV1Channels, info.Name)
h.logger.Debugf("Successfully update config channel: %s", info.URL)
h.sendResponseCreated(resp, info.URL, info)
}
// Expect a multipart/form-data with a single part, of type file, with key FormDataConfigBlockKey.
func (h *HTTPHandler) multipartFormDataBodyToBlock(params map[string]string, req *http.Request, resp http.ResponseWriter) *cb.Block {
boundary := params["boundary"]
reader := multipart.NewReader(
http.MaxBytesReader(resp, req.Body, int64(h.config.MaxRequestBodySize)),
boundary,
)
form, err := reader.ReadForm(2 * int64(h.config.MaxRequestBodySize))
if err != nil {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrap(err, "cannot read form from request body"))
return nil
}
if _, exist := form.File[FormDataConfigBlockKey]; !exist {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Errorf("form does not contains part key: %s", FormDataConfigBlockKey))
return nil
}
if len(form.File) != 1 || len(form.Value) != 0 {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.New("form contains too many parts"))
return nil
}
fileHeader := form.File[FormDataConfigBlockKey][0]
file, err := fileHeader.Open()
if err != nil {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, "cannot open file part %s from request body", FormDataConfigBlockKey))
return nilView on GitHub (pinned to 2736b63f8f)
Solutions
- Increase channelParticipation.maxRequestBodySize in orderer.yaml if the config block is large, and restart
- Re-send with a correct multipart form (curl -F 'config-block=@genesis.block') so boundaries and parts are well-formed
- Verify the uploaded config block file is complete and not truncated (compare checksums)
- Check the wrapped inner error: http: request body too large means raise the size limit; multipart errors mean fix the body format
Example fix
// before (orderer.yaml) ChannelParticipation: MaxRequestBodySize: 1048576 // after ChannelParticipation: MaxRequestBodySize: 10485760
Defensive patterns
Strategy: try-catch
Validate before calling
fi, _ := os.Stat(configBlockPath)
if fi.Size() > maxRequestBodySize {
return fmt.Errorf("config block is %d bytes; raise channelParticipation.maxRequestBodySize (current %d)", fi.Size(), maxRequestBodySize)
} Try / catch
if err != nil && strings.Contains(err.Error(), "cannot read form from request body") {
if strings.Contains(err.Error(), "request body too large") {
// raise ChannelParticipation.MaxRequestBodySize in orderer.yaml
} else {
// malformed multipart: rebuild with curl -F / multipart writer
}
} Prevention
- Size maxRequestBodySize above your largest expected config block
- Upload complete, checksum-verified block files
- Use standard multipart writers instead of hand-built bodies
- Avoid middleware that buffers/truncates request bodies
When it happens
Trigger: serveJoin receiving a body whose multipart encoding is invalid (wrong boundary, missing final boundary, truncated upload) or whose size exceeds orderer config channelParticipation.maxRequestBodySize, causing MaxBytesReader to cut the stream.
Common situations: Config block larger than MaxRequestBodySize (default 1MB) when joining a channel with a big config; network interruption during upload; client library generating a different boundary than advertised in the header; request body modified by middleware.
Related errors
- cannot parse Mime media type
- form does not contains part key: %s
- error reading next multipart
- channel participation API is disabled
- missing channel ID
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/21084d0da7f00add.
Report an issue: GitHub.