hyperledger/fabric · error

signer is nil

Error message

signer is nil

What it means

NodeClientStream.Auth() requires an identity.Signer to authenticate the stream to the remote cluster node. Before building the NodeAuthRequest it checks cs.Signer and returns this error if the Signer field of NodeClientStream is nil. It is a programming/configuration guard: the stream was constructed without the signing identity needed to sign the auth payload.

Source

Thrown at orderer/common/cluster/commauth.go:252

func (cs *NodeClientStream) Send(request *orderer.StepRequest) error {
	stepRequest, cerr := BuildStepRequest(request)
	if cerr != nil {
		return cerr
	}
	return cs.StepClient.Send(stepRequest)
}

func (cs *NodeClientStream) Recv() (*orderer.StepResponse, error) {
	nodeResponse, err := cs.StepClient.Recv()
	if err != nil {
		return nil, err
	}
	return BuildStepRespone(nodeResponse)
}

func (cs *NodeClientStream) Auth() error {
	if cs.Signer == nil {
		return errors.New("signer is nil")
	}

	payload := &orderer.NodeAuthRequest{
		Version:   cs.Version,
		Timestamp: timestamppb.Now(),
		FromId:    cs.SourceNodeID,
		ToId:      cs.DestinationNodeID,
		Channel:   cs.Channel,
	}

	bindingFieldsHash := GetSessionBindingHash(payload)

	tlsBinding, err := GetTLSSessionBinding(cs.StepClient.Context(), bindingFieldsHash)
	if err != nil {
		return errors.Wrap(err, "TLSBinding failed")
	}
	payload.SessionBinding = tlsBinding

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Populate the Signer field when constructing NodeClientStream with a valid identity.Signer obtained from the local MSP/signing identity manager.
  2. Check where the stream is created and ensure the signing identity loaded successfully before wiring it into the stream.
  3. If Auth() is not needed for the stream's purpose, do not call it instead of leaving Signer nil.

Example fix

// before
stream := &cluster.NodeClientStream{
    StepClient: stepClient,
    Version:    1,
}
stream.Auth() // panics-free but returns "signer is nil"
// after
signer, err := localmsp.NewSigner()
if err != nil {
    return err
}
stream := &cluster.NodeClientStream{
    StepClient: stepClient,
    Version:    1,
    Signer:     signer,
}
stream.Auth()
Defensive patterns

Strategy: validation

Validate before calling

if stream == nil || stream.Signer == nil {
    return errors.New("cannot authenticate: stream has no signer configured")
}
err := stream.Auth()

Type guard

func hasSigner(cs *cluster.NodeClientStream) bool {
    return cs != nil && cs.Signer != nil
}

Try / catch

if err := stream.Auth(); err != nil {
    if err.Error() == "signer is nil" {
        // re-create stream with a valid signer
    }
    return fmt.Errorf("auth: %w", err)
}

Prevention

When it happens

Trigger: Calling Auth() on a NodeClientStream whose Signer field was never populated when the stream struct was constructed (NodeClientStream{StepClient: ..., ...} built without assigning an identity.Signer).

Common situations: Test harnesses or custom RPC stream factories that construct NodeClientStream manually and forget the Signer; code paths where a service identity was not loaded (missing MSP config / signing identity) so nil is passed in; refactors that dropped the Signer assignment.

Related errors


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