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.

Solutions

  1. Filter nil entries from the interests slice before building the query
  2. Fix slice construction: use append into a zero-length slice instead of pre-sized make
  3. 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

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


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

Appendix: 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 structure

View on GitHub (pinned to 2736b63f8f)