hyperledger/fabric · error

envelope index out of bounds

Error message

envelope index out of bounds

What it means

ExtractEnvelope returns this error when the requested index is negative or >= the number of envelopes in block.Data.Data, i.e. the caller asked for a transaction slot that does not exist in the block. Each block only carries envelopeCount entries.

Source

Thrown at protoutil/commonutils.go:102

// and unmarshals it -- it panics if either of these operations fail
func ExtractEnvelopeOrPanic(block *cb.Block, index int) *cb.Envelope {
	envelope, err := ExtractEnvelope(block, index)
	if err != nil {
		panic(err)
	}
	return envelope
}

// ExtractEnvelope retrieves the requested envelope from a given block and
// unmarshals it
func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) {
	if block.Data == nil {
		return nil, errors.New("block data is nil")
	}

	envelopeCount := len(block.Data.Data)
	if index < 0 || index >= envelopeCount {
		return nil, errors.New("envelope index out of bounds")
	}
	marshaledEnvelope := block.Data.Data[index]
	envelope, err := GetEnvelopeFromBlock(marshaledEnvelope)
	err = errors.WithMessagef(err, "block data does not carry an envelope at index %d", index)
	return envelope, err
}

// MakeChannelHeader creates a ChannelHeader.
func MakeChannelHeader(headerType cb.HeaderType, version int32, chainID string, epoch uint64) *cb.ChannelHeader {
	tm := timestamppb.Now()
	tm.Nanos = 0
	return &cb.ChannelHeader{
		Type:      int32(headerType),
		Version:   version,
		Timestamp: tm,
		ChannelId: chainID,
		Epoch:     epoch,
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Bound your loop with len(block.Data.Data) rather than a fixed tx count or block batch size.
  2. Check the index source: tx validation codes/txids indexes must be recomputed if they reference indices beyond the block.
  3. Use GetTransactionByID/ledger index APIs instead of hand-tracking envelope indices.
  4. For a zero-transaction block, handle envelopeCount == 0 explicitly before extracting.

Example fix

// before
for i := 0; i < blockSize; i++ { // blockSize from config, may exceed actual
    env, err := protoutil.ExtractEnvelope(block, i)
}
// after
for i := 0; i < len(block.Data.Data); i++ {
    env, err := protoutil.ExtractEnvelope(block, i)
}
Defensive patterns

Strategy: validation

Validate before calling

func envelopeCount(block *cb.Block) int {
    if block == nil || block.Data == nil {
        return 0
    }
    return len(block.Data.Data)
}
// before extracting: if index < 0 || index >= envelopeCount(block) { skip }

Type guard

func validEnvelopeIndex(block *cb.Block, index int) bool {
    return block != nil && block.Data != nil && index >= 0 && index < len(block.Data.Data)
}

Try / catch

env, err := protoutil.ExtractEnvelope(block, i)
if err != nil {
    if strings.Contains(err.Error(), "envelope index out of bounds") {
        logger.Warnf("block %d: index %d out of bounds (%d txs); truncating iteration",
            block.GetHeader().GetNumber(), i, len(block.Data.GetData()))
        break
    }
    return err
}

Prevention

When it happens

Trigger: Calling ExtractEnvelope(block, index) with index < 0 or index >= len(block.Data.Data) — typically iterating with a wrong bound, assuming a fixed number of txs per block, or using an index from another block.

Common situations: Block iteration code using the configured batch size instead of len(block.Data.Data); validators/committers re-processing a block after metadata mismatch; tests passing index 0 on an empty block; duplicated-tx lookup (TestBlockfileMgrGetTxByIdDuplicateTxid) with stale indices.

Related errors


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