hyperledger/fabric · error

signer is required when creating a signed transaction

Error message

signer is required when creating a signed transaction

What it means

CreateSignedTx requires a Signer to sign the assembled transaction; if the signer parameter is nil it returns this error. Even with valid proposal and responses, no signature can be produced without a signing identity.

Source

Thrown at protoutil/txutils.go:148

	Sign(msg []byte) ([]byte, error)
	Serialize() ([]byte, error)
}

// CreateSignedTx assembles an Envelope message from proposal, endorsements,
// and a signer. This function should be called by a client when it has
// collected enough endorsements for a proposal to create a transaction and
// submit it to peers for ordering
func CreateSignedTx(
	proposal *peer.Proposal,
	signer Signer,
	resps ...*peer.ProposalResponse,
) (*common.Envelope, error) {
	if len(resps) == 0 {
		return nil, errors.New("at least one proposal response is required")
	}

	if signer == nil {
		return nil, errors.New("signer is required when creating a signed transaction")
	}

	// the original header
	hdr, err := UnmarshalHeader(proposal.Header)
	if err != nil {
		return nil, err
	}

	// the original payload
	pPayl, err := UnmarshalChaincodeProposalPayload(proposal.Payload)
	if err != nil {
		return nil, err
	}

	// check that the signer is the same that is referenced in the header
	signerBytes, err := signer.Serialize()
	if err != nil {
		return nil, err

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Pass a valid signing identity (e.g. from msp.NewSigningIdentity or the local MSP) to CreateSignedTx
  2. Check that the local MSP and signing identity are loaded before transaction assembly
  3. Verify keystore/certificate paths and that identity retrieval returned non-nil (check err, not just value)
  4. If the code path allows unsigned operation, use the appropriate constructor instead of CreateSignedTx

Example fix

// before
env, err := protoutil.CreateSignedTx(proposal, nil, resps...)
// after
signer, err := localMSP.GetDefaultSigningIdentity()
if err != nil {
    return nil, err
}
env, err := protoutil.CreateSignedTx(proposal, signer, resps...)
Defensive patterns

Strategy: type-guard

Validate before calling

func requireSigner(signer protoutil.Signer) error {
    if signer == nil {
        return fmt.Errorf("signing identity not loaded")
    }
    return nil
}

Type guard

func hasSigner(s protoutil.Signer) bool {
    if s == nil { return false }
    v := reflect.ValueOf(s)
    return !(v.Kind() == reflect.Ptr && v.IsNil())
}

Try / catch

signer, err := localMSP.GetDefaultSigningIdentity()
if err != nil || signer == nil {
    return nil, fmt.Errorf("no signing identity: %w", err)
}
tx, err := protoutil.CreateSignedTx(proposal, signer, resps...)

Prevention

When it happens

Trigger: Calling CreateSignedTx(proposal, nil, resps...) or passing a nil-valued interface (e.g. a nil *msp.SigningIdentity stored in an interface) returned by an unchecked identity lookup.

Common situations: Client not properly initialized with an MSP/signing identity; identity loaded after a config/env var miss; a SigningIdentity variable left nil because credential files were missing.

Related errors


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