hyperledger/fabric · error

invalid txIDKey {%x}, fewer bytes present

Error message

invalid txIDKey {%x}, fewer bytes present

What it means

After decoding the varint length of the TxID, retrieveTxID expects remaining bytes to contain TxID bytes plus BlkNum and TxNum. If the remaining byte count is <= the declared txIDLen, the key is truncated or malformed, and this error reports the hex bytes.

Source

Thrown at common/ledger/blkstorage/blockindex.go:442

// retrieveTxID takes input an encoded txid key of the format `prefix:len(TxID):TxID:BlkNum:TxNum`
// and returns the TxID from this
func retrieveTxID(encodedTxIDKey []byte) (string, error) {
	if len(encodedTxIDKey) == 0 {
		return "", errors.New("invalid txIDKey - zero-length slice")
	}
	if encodedTxIDKey[0] != txIDIdxKeyPrefix {
		return "", errors.Errorf("invalid txIDKey {%x} - unexpected prefix", encodedTxIDKey)
	}
	remainingBytes := encodedTxIDKey[utf8.RuneLen(txIDIdxKeyPrefix):]

	txIDLen, n, err := util.DecodeOrderPreservingVarUint64(remainingBytes)
	if err != nil {
		return "", errors.WithMessagef(err, "invalid txIDKey {%x}", encodedTxIDKey)
	}
	remainingBytes = remainingBytes[n:]
	if len(remainingBytes) <= int(txIDLen) {
		return "", errors.Errorf("invalid txIDKey {%x}, fewer bytes present", encodedTxIDKey)
	}
	return string(remainingBytes[:int(txIDLen)]), nil
}

func retrieveBlockNum(encodedTxIDKey []byte, BlkNumStartingIndex int) (uint64, error) {
	n, _, err := util.DecodeOrderPreservingVarUint64(encodedTxIDKey[BlkNumStartingIndex:])
	return n, err
}

type rangeScan struct {
	startKey []byte
	stopKey  []byte
}

func constructTxIDRangeScan(txID string) *rangeScan {
	sk := append(
		[]byte{txIDIdxKeyPrefix},
		util.EncodeOrderPreservingVarUint64(uint64(len(txID)))...,

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Treat as index corruption: stop the peer and rebuild the block index (reindex from block files or rejoin the channel).
  2. Validate that keys are only produced by constructTxIDKey; never hand-build encoded txID keys.
  3. Check the storage volume for truncation/partial copy issues if ledgers were migrated.
Defensive patterns

Strategy: validation

Validate before calling

// ensure declared txID length fits the available bytes before decoding
remaining := key[1:] // after prefix
_, n, err := util.DecodeOrderPreservingVarUint64(remaining)
if err != nil || n <= 0 || n >= len(remaining) {
    return "", errors.Errorf("malformed txID key: %x", key)
}

Try / catch

txID, err := retrieveTxID(key)
if err != nil && strings.Contains(err.Error(), "fewer bytes present") {
    return fmt.Errorf("truncated txID key %x — rebuild index: %w", key, err)
}
if err != nil { return err }

Prevention

When it happens

Trigger: Truncated or corrupted leveldb values/keys in the txID index, or hand-crafted keys where len(TxID) overstates the actual payload (as exercised in TestTxIDKeyDecodingInvalidInputs).

Common situations: Index corruption from partial writes, manually copied or truncated DB files, or unit tests validating decoder robustness against length mismatches.

Related errors


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