hyperledger/fabric · error
cannot unmarshal file part %s into an envelope
Error message
cannot unmarshal file part %s into an envelope
What it means
This HTTP 400 error wraps a proto.Unmarshal failure when the bytes from the multipart file part cannot be decoded into a common.Envelope. The endpoint expects the file part to contain a protobuf-marshaled cb.Envelope (a config update transaction); any other content - JSON, PEM, base64 text, a genesis block, or arbitrary data - fails unmarshaling.
Source
Thrown at orderer/common/channelparticipation/restapi.go:510
fileHeader := form.File[FormDataConfigUpdateEnvelopeKey][0]
file, err := fileHeader.Open()
if err != nil {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, "cannot open file part %s from request body", FormDataConfigUpdateEnvelopeKey))
return nil
}
envelopeBytes, err := io.ReadAll(file)
if err != nil {
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, "cannot read file part %s from request body", FormDataConfigUpdateEnvelopeKey))
return nil
}
envelope := &cb.Envelope{}
err = proto.Unmarshal(envelopeBytes, envelope)
if err != nil {
h.logger.Debugf("Failed to unmarshal envelopeBytes: %s", err)
h.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, "cannot unmarshal file part %s into an envelope", FormDataConfigUpdateEnvelopeKey))
return nil
}
return envelope
}
func (h *HTTPHandler) extractChannelID(req *http.Request, resp http.ResponseWriter) (string, error) {
channelID, ok := mux.Vars(req)[channelIDKey]
if !ok {
err := errors.New("missing channel ID")
h.sendResponseJsonError(resp, http.StatusInternalServerError, err)
return "", err
}
if err := configtx.ValidateChannelID(channelID); err != nil {
err = errors.WithMessage(err, "invalid channel ID")
h.sendResponseJsonError(resp, http.StatusBadRequest, err)
return "", errView on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the file contains raw protobuf Envelope bytes (e.g. produced by configtxlator or configtxgen tooling), not JSON or base64 - decode base64 first if applicable.
- Re-generate the config update envelope: create the config update with configtxlator, compute the update, sign it, and marshal it as an Envelope.
- Ensure you are not uploading a genesis block or common.Block; this API takes only the config update Envelope.
- Check the file is complete (compare byte size/checksum against the producer) and that no wrapper text or HTML was captured into it.
Example fix
// before: uploading base64-encoded or JSON data
body := base64.StdEncoding.EncodeToString(envelopeBytes)
// after: upload the raw protobuf envelope bytes
body := envelopeBytes // proto.Marshal(&cb.Envelope{...}) output, written directly Defensive patterns
Strategy: validation
Validate before calling
function looksLikeEnvelope(bytes: Uint8Array): boolean {
// wire-format check: Envelope.ChannelHeader is field 1, bytes => tag 0x0a followed by varint length
if (bytes.length < 2) return false
return bytes[0] === 0x0a && bytes[1] > 0
}
// call before upload:
if (!looksLikeEnvelope(envelopeBytes)) throw new Error('file is not raw protobuf Envelope bytes (JSON/base64/block?)') Type guard
function isProtoEnvelopeBytes(x: unknown): x is Uint8Array {
return x instanceof Uint8Array && x.length > 1 && x[0] === 0x0a
} Try / catch
try {
const resp = await fetch(url, { method: 'PUT', body: formData })
if (resp.status === 400) {
const msg = await resp.text()
if (msg.includes('cannot unmarshal file part')) {
// bytes were not a protobuf Envelope: check for base64/JSON and re-encode
}
}
} catch (e) { /* transport error */ } Prevention
- Always upload raw proto.Marshal(cb.Envelope) bytes; decode base64 first if your tooling emits base64.
- Never upload genesis blocks, common.Block files, JSON channel config, or PEM files to this endpoint.
- Round-trip validate locally: proto.Unmarshal the bytes before sending to confirm they parse.
- Confirm the file producer (configtxlator/configtxgen) output and that no wrapper/HTML text was captured into the file.
When it happens
Trigger: The uploaded file part contains bytes that are not a valid protobuf Envelope: a JSON config update, a base64-encoded envelope, a common.Block/genesis block, an HTML error page, or a truncated envelope.
Common situations: Uploading a genesis block or channel config JSON instead of the signed config update envelope; exporting the envelope but base64-encoding it (osnadmin/channel join scripts encode to base64 while this API expects raw proto bytes); pointing the client at an HTML login/error page captured as the body; sending a partially written file.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- failed to deserialize values
- error converting envelope to config update: %s
- failed to unmarshal response for transaction %s
- unmarshalling ChaincodeQueryResponse failed
- could not unmarshal chaincode package to CDS or SignedCDS
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/3b73197f455ea0fa.
Report an issue: GitHub.