hyperledger/fabric · error
transaction %d has no signature
Error message
transaction %d has no signature
What it means
VerifyTransactionsAreWellFormed requires every envelope in a block to carry a signature. If proto.Unmarshal succeeded but env.Signature is empty, the transaction is unsigned and cannot be authenticated, so the function rejects it. This mirrors the payload check and enforces the Envelope invariant that both Payload and Signature must be set.
Source
Thrown at protoutil/blockutils.go:338
// If we have a single transaction, and the block is a config block, then no need to check
// well formed-ness, because there cannot be another transaction in the original block.
if HasConfigTx(bd) {
return nil
}
for i, rawTx := range bd.Data {
env := &cb.Envelope{}
if err := proto.Unmarshal(rawTx, env); err != nil {
return fmt.Errorf("transaction %d is invalid: %v", i, err)
}
if len(env.Payload) == 0 {
return fmt.Errorf("transaction %d has no payload", i)
}
if len(env.Signature) == 0 {
return fmt.Errorf("transaction %d has no signature", i)
}
expected, err := proto.Marshal(env)
if err != nil {
return fmt.Errorf("failed re-marshaling envelope: %v", err)
}
if len(expected) < len(rawTx) {
return fmt.Errorf("transaction %d has %d trailing bytes", i, len(rawTx)-len(expected))
}
if !bytes.Equal(expected, rawTx) {
return fmt.Errorf("transaction %d (%s) does not match its raw form (%s)", i,
base64.StdEncoding.EncodeToString(expected), base64.StdEncoding.EncodeToString(rawTx))
}
}
return nil
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the envelope was signed before marshaling: set env.Signature from the signer over the serialized Payload.
- Verify the block source — if a peer produced this block, compare with other replicas to determine if data is corrupt.
- In test code, use protoutil helpers that build signed envelopes rather than hand-constructing &cb.Envelope{}.
- Reject unsigned envelopes at ingestion before they ever reach a block.
Example fix
// before
env := &cb.Envelope{Payload: payloadBytes}
// after
sig, err := signer.Sign(payloadBytes)
if err != nil { return err }
env := &cb.Envelope{Payload: payloadBytes, Signature: sig} Defensive patterns
Strategy: validation
Validate before calling
env := &cb.Envelope{}
if err := proto.Unmarshal(rawTx, env); err != nil { return err }
if len(env.Signature) == 0 {
return fmt.Errorf("tx %d: unsigned envelope", i)
} Type guard
func isSigned(env *cb.Envelope) bool { return env != nil && len(env.Signature) > 0 } Prevention
- Sign every envelope over its serialized Payload before marshaling.
- Use msp/signing helpers instead of manual signature handling.
- Never strip or overwrite env.Signature when transforming envelopes.
- Test fixtures should use the same signing path as production code.
When it happens
Trigger: BlockDataHash encounters, at transaction index i, an Envelope whose Signature byte slice is empty — typically an envelope constructed programmatically without calling Sign, or one whose signature was stripped.
Common situations: Test fixtures building envelopes with only Payload set; code that re-marshals envelopes and drops the Signature field; envelopes deserialized from a truncated/corrupted block; forgetting env.Signature = signer.Sign(payload).
Related errors
- transaction %d has no payload
- transaction %d has %d trailing bytes
- transaction %d (%s) does not match its raw form (%s)
- malformed org definition for org: %s
- error encode input
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/784a3a5340778302.
Report an issue: GitHub.