hyperledger/fabric · error
chaincode interest is nil
Error message
chaincode interest is nil
What it means
validateInterests iterates the provided ChaincodeInterest objects and fails if any individual element is nil. A nil interest cannot describe any chaincode to endorse, so the whole query is rejected before being sent to the discovery service.
Source
Thrown at discovery/client/client.go:609
if si == nil {
return errors.New("message isn't a stateInfo message")
}
if si.Timestamp == nil {
return errors.New("timestamp is nil")
}
if si.Properties == nil {
return errors.New("properties is nil")
}
return nil
}
func validateInterests(interests ...*peer.ChaincodeInterest) error {
if len(interests) == 0 {
return errors.New("no chaincode interests given")
}
for _, interest := range interests {
if interest == nil {
return errors.New("chaincode interest is nil")
}
if err := InvocationChain(interest.Chaincodes).ValidateInvocationChain(); err != nil {
return err
}
}
return nil
}
// InvocationChain aggregates ChaincodeCalls
type InvocationChain []*peer.ChaincodeCall
// String returns a string representation of this invocation chain
func (ic InvocationChain) String() string {
s, _ := json.Marshal(ic)
return string(s)
}
// ValidateInvocationChain validates the InvocationChain's structureView on GitHub (pinned to 2736b63f8f)
Solutions
- Filter nil entries from the interests slice before building the query
- Fix slice construction: use append into a zero-length slice instead of pre-sized make
- Add an application-level check that every element is non-nil before calling AddEndorsersQuery
Example fix
// before
interests := make([]*peer.ChaincodeInterest, len(chaincodes))
for i, cc := range chaincodes {
if cc == nil { continue } // leaves nil holes
interests[i] = discovery.ChaincodeInterest{...}
}
req := discovery.NewEndorsersQuery(interests...) // panics/validation error
// after
var interests []*peer.ChaincodeInterest
for _, cc := range chaincodes {
if cc == nil { continue }
interests = append(interests, discovery.ChaincodeInterest{Chaincodes: ...})
}
if len(interests) == 0 { return errors.New("no chaincodes selected") }
req := discovery.NewEndorsersQuery(interests...) Defensive patterns
Strategy: validation
Validate before calling
func dropNilInterests(interests []*peer.ChaincodeInterest) []*peer.ChaincodeInterest {
out := make([]*peer.ChaincodeInterest, 0, len(interests))
for _, i := range interests {
if i != nil { out = append(out, i) }
}
return out
} Type guard
func allInterestsNonNil(interests []*peer.ChaincodeInterest) bool {
for _, i := range interests { if i == nil { return false } }
return len(interests) > 0
} Try / catch
if err != nil && strings.Contains(err.Error(), "chaincode interest is nil") {
return fmt.Errorf("nil entry in interests slice: %w", err)
} Prevention
- Build slices with append, not pre-sized make with indexed writes
- Filter nils before NewEndorsersQuery
- Add unit tests for interest-slice construction
When it happens
Trigger: Calling discovery.NewEndorsersQuery(i1, nil) or AddEndorsersQuery with a slice that contains a nil *peer.ChaincodeInterest element (e.g. built by appending into a pre-sized slice make([]*peer.ChaincodeInterest, n)).
Common situations: Building interests in a loop with make([]..., 0, n) vs make([]..., n) and appending into indexed slots that stay nil; JSON/config parsing leaving optional chaincode entries as nil.
Related errors
- no chaincode interests given
- expected %d endorsement descriptors but got only %d
- expected chaincode %s but got endorsement descriptor for %s
- failed constructing descriptor for %v
- block must be different from nil, channel=%s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/23d71f3b776cc32e.
Report an issue: GitHub.