hyperledger/fabric · error

transaction %d is invalid: %v

Error message

transaction %d is invalid: %v

What it means

VerifyTransactionsAreWellFormed iterates the block's data envelopes and proto-unmarshals each into cb.Envelope. If any envelope fails to parse, it returns this error naming the transaction index and the underlying parse failure, identifying the exact corrupt entry in the block.

Source

Thrown at protoutil/blockutils.go:330

	}
	return nil
}

func VerifyTransactionsAreWellFormed(bd *cb.BlockData) error {
	if bd == nil || bd.Data == nil || len(bd.Data) == 0 {
		return errors.New("empty block")
	}

	// 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))
		}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Identify which data source produced the block and re-fetch the block from a healthy ordering node or peer
  2. Run ledger integrity checks / rebuild the ledger if many blocks fail the same way
  3. Verify storage health (disk, filesystem) when corruption is recurring
  4. If the corruption came from a restore/migration, redo it from a verified backup

Example fix

// before
env := &cb.Envelope{}
if err := proto.Unmarshal(rawTx, env); err != nil {
    return fmt.Errorf("transaction %d is invalid: %v", i, err)
}
// after
env := &cb.Envelope{}
if err := proto.Unmarshal(rawTx, env); err != nil {
    return fmt.Errorf("transaction %d (len %d) is invalid: %v", i, len(rawTx), err)
}
if len(rawTx) == 0 {
    return fmt.Errorf("transaction %d is empty", i)
}
Defensive patterns

Strategy: validation

Validate before calling

for i, rawTx := range block.Data.Data {
    probe := &cb.Envelope{}
    if len(rawTx) == 0 || proto.Unmarshal(rawTx, probe) != nil {
        return fmt.Errorf("envelope %d in block %d is corrupt", i, block.GetHeader().GetNumber())
    }
}
err := VerifyTransactionsAreWellFormed(block.Data)

Type guard

func isParseableEnvelope(raw []byte) (*cb.Envelope, bool) {
    env := &cb.Envelope{}
    if len(raw) == 0 || proto.Unmarshal(raw, env) != nil || len(env.GetPayload()) == 0 {
        return nil, false
    }
    return env, true
}

Try / catch

if err := VerifyTransactionsAreWellFormed(block.Data); err != nil {
    logger.Errorf("corrupt transactions detected: %v — re-fetching block", err)
    return refetchBlock(block.GetHeader().GetNumber())
}

Prevention

When it happens

Trigger: Calling VerifyTransactionsAreWellFormed on a block where Data[i] bytes are not a valid protobuf Envelope — truncated writes, corrupted ledger segments, or a producer writing non-envelope payloads.

Common situations: Disk corruption on file-ledger nodes, blocks truncated during snapshot/restore, or a misbehaving ordering node emitting malformed envelopes.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


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