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 structure

View on GitHub (pinned to 2736b63f8f)

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.