hyperledger/fabric · error

unmarshal failed

Error message

unmarshal failed

What it means

HandleGetState parses msg.Payload as pb.GetState using proto.Unmarshal; the "unmarshal failed" error (wrapped) means the payload bytes are not a valid protobuf GetState message. This is peer-side defense against malformed chaincode-to-peer GET_STATE messages — the request never reaches the ledger.

Source

Thrown at core/chaincode/handler.go:683

		Collection: collection,
	}

	readP, writeP, err := txContext.CollectionStore.RetrieveReadWritePermission(cc, txContext.SignedProp, txContext.TXSimulator)
	if err != nil {
		return nil, err
	}
	rwPermission := &readWritePermission{read: readP, write: writeP}
	txContext.CollectionACLCache.put(collection, rwPermission)

	return rwPermission, nil
}

// Handles query to ledger to get state
func (h *Handler) HandleGetState(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 state for chaincode %s, key %s, channel %s", shorttxid(msg.Txid), namespaceID, getState.Key, txContext.ChannelID)

	if isCollectionSet(collection) {
		if txContext.IsInitTransaction {
			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.GetPrivateData(namespaceID, collection, getState.Key)
	} else {
		res, err = txContext.TXSimulator.GetState(namespaceID, getState.Key)
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Use the official fabric-chaincode-go shim (fabric-sdk or language shim) so GetState is serialized as pb.GetState protobuf
  2. Rebuild/redeploy the chaincode with a shim version compatible with the peer's protobuf definitions
  3. If testing peer internals, marshal payload via proto.Marshal(&pb.GetState{Key: ..., Collection: ...})
  4. Check for truncated payloads if messages pass through proxies/custom transports

Example fix

// before: hand-built payload
payload := []byte("key=mykey")
// after
payload, _ := proto.Marshal(&pb.GetState{Key: "mykey"})
msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: payload, Txid: txid}
Defensive patterns

Strategy: type-guard

Type guard

func validGetStatePayload(p []byte) bool {
    var gs pb.GetState
    return proto.Unmarshal(p, &gs) == nil && gs.Key != ""
}

Prevention

When it happens

Trigger: Chaincode shim sends a GET_STATE message whose payload is empty, truncated, or was serialized with a different/incompatible schema; custom or hand-rolled shim implementations that put wrong bytes in the payload; shim/peer protobuf version mismatch.

Common situations: Custom chaincode implementations in non-Go languages hand-building messages; shim and peer versions significantly out of sync; network/transport corruption in experimental setups; tests constructing ChaincodeMessage payloads incorrectly.

Related errors


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