{"record":{"id":"3b73197f455ea0fa","repo":"hyperledger/fabric","slug":"cannot-unmarshal-file-part-s-into-an-envelope","errorCode":null,"errorMessage":"cannot unmarshal file part %s into an envelope","messagePattern":"cannot unmarshal file part (.+?) into an envelope","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"orderer/common/channelparticipation/restapi.go","lineNumber":510,"sourceCode":"\n\tfileHeader := form.File[FormDataConfigUpdateEnvelopeKey][0]\n\tfile, err := fileHeader.Open()\n\tif err != nil {\n\t\th.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, \"cannot open file part %s from request body\", FormDataConfigUpdateEnvelopeKey))\n\t\treturn nil\n\t}\n\n\tenvelopeBytes, err := io.ReadAll(file)\n\tif err != nil {\n\t\th.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, \"cannot read file part %s from request body\", FormDataConfigUpdateEnvelopeKey))\n\t\treturn nil\n\t}\n\n\tenvelope := &cb.Envelope{}\n\terr = proto.Unmarshal(envelopeBytes, envelope)\n\tif err != nil {\n\t\th.logger.Debugf(\"Failed to unmarshal envelopeBytes: %s\", err)\n\t\th.sendResponseJsonError(resp, http.StatusBadRequest, errors.Wrapf(err, \"cannot unmarshal file part %s into an envelope\", FormDataConfigUpdateEnvelopeKey))\n\t\treturn nil\n\t}\n\n\treturn envelope\n}\n\nfunc (h *HTTPHandler) extractChannelID(req *http.Request, resp http.ResponseWriter) (string, error) {\n\tchannelID, ok := mux.Vars(req)[channelIDKey]\n\tif !ok {\n\t\terr := errors.New(\"missing channel ID\")\n\t\th.sendResponseJsonError(resp, http.StatusInternalServerError, err)\n\t\treturn \"\", err\n\t}\n\n\tif err := configtx.ValidateChannelID(channelID); err != nil {\n\t\terr = errors.WithMessage(err, \"invalid channel ID\")\n\t\th.sendResponseJsonError(resp, http.StatusBadRequest, err)\n\t\treturn \"\", err","sourceCodeStart":492,"sourceCodeEnd":528,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/channelparticipation/restapi.go#L492-L528","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: uploading base64-encoded or JSON data\nbody := base64.StdEncoding.EncodeToString(envelopeBytes)\n// after: upload the raw protobuf envelope bytes\nbody := envelopeBytes // proto.Marshal(&cb.Envelope{...}) output, written directly","handlingStrategy":"validation","validationCode":"function looksLikeEnvelope(bytes: Uint8Array): boolean {\n  // wire-format check: Envelope.ChannelHeader is field 1, bytes => tag 0x0a followed by varint length\n  if (bytes.length < 2) return false\n  return bytes[0] === 0x0a && bytes[1] > 0\n}\n// call before upload:\nif (!looksLikeEnvelope(envelopeBytes)) throw new Error('file is not raw protobuf Envelope bytes (JSON/base64/block?)')","typeGuard":"function isProtoEnvelopeBytes(x: unknown): x is Uint8Array {\n  return x instanceof Uint8Array && x.length > 1 && x[0] === 0x0a\n}","tryCatchPattern":"try {\n  const resp = await fetch(url, { method: 'PUT', body: formData })\n  if (resp.status === 400) {\n    const msg = await resp.text()\n    if (msg.includes('cannot unmarshal file part')) {\n      // bytes were not a protobuf Envelope: check for base64/JSON and re-encode\n    }\n  }\n} catch (e) { /* transport error */ }","preventionTips":["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."],"tags":["http","protobuf","unmarshal","hyperledger-fabric"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}