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
- Use the official fabric-chaincode-go shim (fabric-sdk or language shim) so GetState is serialized as pb.GetState protobuf
- Rebuild/redeploy the chaincode with a shim version compatible with the peer's protobuf definitions
- If testing peer internals, marshal payload via proto.Marshal(&pb.GetState{Key: ..., Collection: ...})
- 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
- Always build GET_STATE payloads with proto.Marshal(&pb.GetState{...})
- Keep the shim version aligned with the peer's protobuf definitions
- Never hand-assemble protobuf payload bytes in custom shims/tests
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
- error marshaling
- failed to unmarshal response for transaction %s
- marshal failed
- could not unmarshal chaincode package to CDS or SignedCDS
- failed to unmarshal deployment spec from bytes
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/76bc0ae0e7cfff1e.
Report an issue: GitHub.