hyperledger/fabric · error
cannot unmarshal file part %s into a block
Error message
cannot unmarshal file part %s into a block
What it means
This error wraps a proto.Unmarshal failure: the bytes uploaded as the 'config-block' file part are not a valid protobuf-encoded common.Block. The handler logs the unmarshal failure at debug level and returns HTTP 400 with this message. It means the payload arrived intact but is not the expected block format (wrong file, corrupted, base64/JSON instead of raw protobuf bytes).
Source
Thrown at orderer/common/channelparticipation/restapi.go:463
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 nil
}
blockBytes, err := io.ReadAll(file)
if err != nil {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, "cannot read file part %s from request body", FormDataConfigBlockKey))
return nil
}
block := &cb.Block{}
err = proto.Unmarshal(blockBytes, block)
if err != nil {
h.logger.Debugf("Failed to unmarshal blockBytes: %s", err)
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, "cannot unmarshal file part %s into a block", FormDataConfigBlockKey))
return nil
}
return block
}
// Expect a multipart/form-data with a single part, of type file, with key FormDataConfigUpdateEnvelopeKey.
func (h *HTTPHandler) multipartFormDataBodyToEnvelope(params map[string]string, req *http.Request, resp http.ResponseWriter) *cb.Envelope {
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
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Regenerate the genesis block with configtxgen (configtxgen -profile ... -outputBlock genesis.block) and upload that raw file
- Ensure the client sends the raw protobuf block bytes, not base64 or JSON representations — decode first if your tooling encodes it
- Verify the file with 'configtxgen -inspectBlock genesis.block' or 'osnadmin channel join' prerequisites before uploading
- Confirm you are attaching the correct file (genesis/config block), not a config-update envelope or certificate
Example fix
# before: uploading base64-encoded block base64 genesis.block | curl -X POST .../join -F 'config-block=@-;type=application/octet-stream' # after: upload raw block bytes curl -X POST .../join -F 'config-block=@genesis.block'
Defensive patterns
Strategy: validation
Validate before calling
// validate the block parses before uploading
block := &common.Block{}
if err := proto.Unmarshal(blockBytes, block); err != nil {
return fmt.Errorf("%s is not a valid protobuf block: %w", blockPath, err)
}
// optionally sanity-check the header
if block.Header == nil || block.Header.Number != 0 {
return errors.New("expected a genesis block (number 0) with a header")
} Type guard
func isProtoBlock(b []byte) bool {
blk := &common.Block{}
return proto.Unmarshal(b, blk) == nil && blk.Header != nil
} Try / catch
if resp.StatusCode == http.StatusBadRequest {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("invalid config-block payload (check it is a raw protobuf block, not base64/JSON): %s", body)
} Prevention
- Generate blocks only via 'configtxgen -outputBlock' and upload the raw file
- Never base64- or JSON-encode the block before upload
- Validate locally with 'configtxgen -inspectBlock' before joining
When it happens
Trigger: POSTing to /participation/v1/channels/{channel}/join with a 'config-block' part whose bytes do not deserialize into a cb.Block — e.g. a JSON/block-string config, a transaction envelope, a PEM cert, or a text error page saved as the block file.
Common situations: Using 'configtxgen -outputBlock' output incorrectly transformed (base64-encoded by a script); downloading the genesis block via an API that returns JSON and re-uploading it raw; accidentally attaching the wrong file (TLS cert, channel tx); truncated block written by a failed fetch.
Related errors
- error unmarshalling
- error encoding output
- error unmarshalling original config
- error unmarshalling updated config
- config must contain a channel group
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/929586c3bb15b9d6.
Report an issue: GitHub.