hyperledger/fabric · error
chaincode spec is nil
Error message
chaincode spec is nil
What it means
InvokedChaincodeName parses a SignedProposal's payload into a ChaincodeInvocationSpec and returns the invoked chaincode's name. After unmarshaling the proposal payload, if the ChaincodeInvocationSpec has a nil ChaincodeSpec there is no invoked chaincode to identify, so the function returns this error.
Source
Thrown at protoutil/proputils.go:431
err := proto.Unmarshal(proposalBytes, proposal)
if err != nil {
return "", errors.WithMessage(err, "could not unmarshal proposal")
}
proposalPayload := &peer.ChaincodeProposalPayload{}
err = proto.Unmarshal(proposal.Payload, proposalPayload)
if err != nil {
return "", errors.WithMessage(err, "could not unmarshal chaincode proposal payload")
}
cis := &peer.ChaincodeInvocationSpec{}
err = proto.Unmarshal(proposalPayload.Input, cis)
if err != nil {
return "", errors.WithMessage(err, "could not unmarshal chaincode invocation spec")
}
if cis.ChaincodeSpec == nil {
return "", errors.Errorf("chaincode spec is nil")
}
if cis.ChaincodeSpec.ChaincodeId == nil {
return "", errors.Errorf("chaincode id is nil")
}
return cis.ChaincodeSpec.ChaincodeId.Name, nil
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Populate the ChaincodeInvocationSpec's ChaincodeSpec (including ChaincodeId and Input) before signing and sending the proposal.
- Validate the proposal construction path in your SDK/CLI so cis.ChaincodeSpec is always set for invoke proposals.
- If the proposal came from the wire, treat it as malformed and reject it; re-fetch or have the client rebuild the transaction.
- Check proto marshaling of the upstream proposal — ensure the right message type was serialized into Payload.Input.
Example fix
// before
cis := &peer.ChaincodeInvocationSpec{}
// after
cis := &peer.ChaincodeInvocationSpec{
ChaincodeSpec: &peer.ChaincodeSpec{
Type: peer.ChaincodeSpec_NODE,
ChaincodeId: &peer.ChaincodeID{Name: "mycc"},
Input: &peer.ChaincodeInput{Args: args},
},
} Defensive patterns
Strategy: validation
Validate before calling
var cis peer.ChaincodeInvocationSpec
if err := proto.Unmarshal(proposalPayload.Input, &cis); err != nil {
return err
}
if cis.ChaincodeSpec == nil {
return errors.New("proposal has no ChaincodeSpec")
} Type guard
func hasChaincodeSpec(cis *peer.ChaincodeInvocationSpec) bool {
return cis != nil && cis.ChaincodeSpec != nil
} Try / catch
name, err := protoutil.InvokedChaincodeName(signedProp)
if err != nil {
return fmt.Errorf("malformed proposal (no chaincode spec): %w", err)
} Prevention
- Construct invoke proposals with an SDK helper that always sets ChaincodeInvocationSpec.ChaincodeSpec.
- Reject proposals at the ingress path when the payload cannot fully unmarshal with a spec.
- Test hand-built proposals against InvokedChaincodeName in CI.
- Log the proposal channel header type alongside the error to distinguish malformed client traffic.
When it happens
Trigger: Submitting a SignedProposal whose payload.Input unmarshals to a ChaincodeInvocationSpec with no ChaincodeSpec set — e.g. a proposal built with an empty ChaincodeInvocationSpec or with only the decorator/args fields left unset.
Common situations: Manually assembled proposals in tests missing ChaincodeSpec; corrupted or truncated payload bytes that decode but leave fields empty; SDK calls that send an invoke proposal with an unset spec after failed construction.
Related errors
- no chaincode name is provided, channel id [%s]
- invalid message for creating lifecycle chaincode proposal
- chaincode id is nil
- error unmarshalling ChaincodeHeaderExtension
- only applicable for private data
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/65aa93d6458cce09.
Report an issue: GitHub.