hyperledger/fabric · error

marshal failed

Error message

marshal failed

What it means

After fetching the values, the handler serializes pb.GetStateMultipleResult back to the chaincode with proto.Marshal. If Marshal fails (extremely rare; e.g. internal protobuf state corruption), the error is wrapped with 'marshal failed' and returned to the shim as an ERROR message. This is a server-side serialization failure, not caused by user input format.

Source

Thrown at core/chaincode/handler.go:746

			return nil, errors.New("private data APIs are not allowed in chaincode Init()")
		}
		if err = errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil {
			return nil, err
		}
		res, err = txContext.TXSimulator.GetPrivateDataMultipleKeys(namespaceID, collection, getState.GetKeys())
	} else {
		res, err = txContext.TXSimulator.GetStateMultipleKeys(namespaceID, getState.GetKeys())
	}
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if len(res) == 0 {
		chaincodeLogger.Debugf("[%s] No state associated with keys: %v. Sending %s with an empty payload", shorttxid(msg.Txid), getState.GetKeys(), pb.ChaincodeMessage_RESPONSE)
	}

	payloadBytes, err := proto.Marshal(&pb.GetStateMultipleResult{Values: res})
	if err != nil {
		return nil, errors.Wrap(err, "marshal failed")
	}

	// Send response msg back to chaincode. GetState will not trigger event
	return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: payloadBytes, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
}

func (h *Handler) HandleGetPrivateDataHash(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
	getState := &pb.GetState{}
	err := proto.Unmarshal(msg.Payload, getState)
	if err != nil {
		return nil, errors.Wrap(err, "unmarshal failed")
	}

	var res []byte
	namespaceID := txContext.NamespaceID
	collection := getState.Collection
	chaincodeLogger.Debugf("[%s] getting private data hash for chaincode %s, key %s, channel %s", shorttxid(msg.Txid), namespaceID, getState.Key, txContext.ChannelID)
	if txContext.IsInitTransaction {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Rebuild the peer with consistent, pinned protobuf/gogo-protobuf versions.
  2. Check the fetched values res for nil sub-messages or invalid byte slices that confuse the marshaller.
  3. Upgrade Hyperledger Fabric to a version with matching generated pb code.
  4. Inspect peer logs for the underlying wrapped error for the exact cause.
Defensive patterns

Strategy: retry

Type guard

func marshalableResult(values [][]byte) bool { _, err := proto.Marshal(&pb.GetStateMultipleResult{Values: values}); return err == nil }

Try / catch

payload, err := stub.GetStateByMultipleKeys(collection, keys)
if err != nil && strings.Contains(err.Error(), "marshal failed") {
    // retry once; if persistent, escalate to peer upgrade
    return retryGetState(keys)
}

Prevention

When it happens

Trigger: proto.Marshal(&pb.GetStateMultipleResult{Values: res}) fails — practically only when protobuf internal marshaling errors (e.g. nested message set to an invalid state) or resource/size issues occur.

Common situations: Very rare in practice; seen with corrupted protobuf runtime, exotic value bytes, or version-skewed generated code between the peer's protos and its protoc-gen-go runtime.

Related errors


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