hyperledger/fabric · error
proto: Marshal called with nil
Error message
proto: Marshal called with nil
What it means
putChaincodeData rejects a nil *ccprovider.ChaincodeData before attempting proto.Marshal, returning the same message the protobuf library uses for nil messages. LSCC requires a valid ChaincodeData to persist the chaincode definition to the ledger; passing nil is a programming error in the caller (e.g., executeChaincode/GetChaincodeToInstall flow constructed no chaincode data).
Source
Thrown at core/scc/lscc/lscc.go:327
chaincodeData := &ccprovider.ChaincodeData{}
err = proto.Unmarshal(chaincodeDataBytes, chaincodeData)
if err != nil {
// this kind of data corruption is unexpected since our code
// always marshals ChaincodeData into these keys
unexpectedErr = errors.Wrapf(err, "chaincode %s has bad definition", chaincodeName)
return
}
plugin = chaincodeData.Vscc
args = chaincodeData.Policy
return
}
// create the chaincode on the given chain
func (lscc *SCC) putChaincodeData(stub shim.ChaincodeStubInterface, cd *ccprovider.ChaincodeData) error {
if cd == nil {
return errors.New("proto: Marshal called with nil")
}
cdbytes, err := proto.Marshal(cd)
if err != nil {
return err
}
if cdbytes == nil {
return MarshallErr(cd.Name)
}
err = stub.PutState(cd.Name, cdbytes)
return err
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the ChaincodeData passed to putChaincodeData is fully populated (name, version, path, Vscc, Policy, Escc, Id) before persisting.
- Check the caller that builds the ChaincodeData for early error returns that leave it nil; propagate those errors instead of continuing.
- If patching/forking lscc, add the nil check (as upstream does) so the failure is explicit rather than a proto.Marshal panic-style error.
Example fix
// before
cd := buildChaincodeData(spec) // may return nil on parse failure
lscc.putChaincodeData(stub, cd)
// after
cd := buildChaincodeData(spec)
if cd == nil {
return fmt.Errorf("failed to build ChaincodeData for %s", spec.ChaincodeSpec.ChaincodeId.Name)
}
lscc.putChaincodeData(stub, cd) Defensive patterns
Strategy: validation
Validate before calling
// guard the ChaincodeData before the LSCC persist path
func validChaincodeData(cd *ccprovider.ChaincodeData) bool {
return cd != nil && cd.Name != "" && cd.Version != "" && cd.Vscc != "" && cd.Escc != ""
} Type guard
func isNilChaincodeData(cd *ccprovider.ChaincodeData) bool { return cd == nil || reflect.ValueOf(cd).IsNil() } Try / catch
// Go: check error from the deploy path and report nil-data programming bugs
if err := lscc.Invoke(stub); err != nil {
if strings.Contains(err.Error(), "Marshal called with nil") {
return fmt.Errorf("internal: ChaincodeData was nil before persist: %w", err)
}
return err
} Prevention
- Construct ChaincodeData via ccprovider helpers rather than ad-hoc structs.
- Always check errors from the step that parses the deployment spec before persisting its data.
- Add unit tests covering the nil-data branch of persist functions.
- Keep LSCC fork/patch code in sync with upstream nil checks.
When it happens
Trigger: Calling lscc.putChaincodeData (via LSCC deploy/instantiate processing) with cd == nil — typically when a deploy path fails to build a ChaincodeData from the deployment spec before persisting it.
Common situations: Custom lifecycle code or forks of lscc that construct ChaincodeData conditionally and skip error checks; upstream bug paths where an earlier parse of the ChaincodeDeploymentSpec returned no data but the flow continued to putChaincodeData.
Related errors
- failed unmarshalling lscc read value into ChaincodeData
- unmarshalling ChaincodeQueryResponse failed
- malformed chaincode invocation spec
- unmarshalling of ChaincodeData failed, error %s
- unmarshalling of ChaincodeData failed, error %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/16439a6ae3fd6187.
Report an issue: GitHub.