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 "", err

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. 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.
  2. Re-generate the config update envelope: create the config update with configtxlator, compute the update, sign it, and marshal it as an Envelope.
  3. Ensure you are not uploading a genesis block or common.Block; this API takes only the config update Envelope.
  4. 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

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


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/3b73197f455ea0fa. Report an issue: GitHub.