{"record":{"id":"0fc2df3e786828ab","repo":"hyperledger/fabric","slug":"index-d-out-of-bounds-total-d-blocks","errorCode":null,"errorMessage":"index %d out of bounds (total %d blocks)","messagePattern":"index (.+?) out of bounds \\(total (.+?) blocks\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/util.go","lineNumber":220,"sourceCode":"\tclientConfigCopy.SecOpts.ServerRootCAs = endpointCriteria.TLSRootCAs\n\n\treturn clientConfigCopy.Dial(endpointCriteria.Endpoint)\n}\n\n// BlockSequenceVerifier verifies that the given consecutive sequence\n// of blocks is valid.\ntype BlockSequenceVerifier func(blocks []*common.Block, channel string) error\n\n// Dialer creates a gRPC connection to a remote address\ntype Dialer interface {\n\tDial(endpointCriteria EndpointCriteria) (*grpc.ClientConn, error)\n}\n\n// VerifyBlockHash verifies the hash chain of the block with the given index\n// among the blocks of the given block buffer.\nfunc VerifyBlockHash(indexInBuffer int, blockBuff []*common.Block) error {\n\tif len(blockBuff) <= indexInBuffer {\n\t\treturn errors.Errorf(\"index %d out of bounds (total %d blocks)\", indexInBuffer, len(blockBuff))\n\t}\n\tblock := blockBuff[indexInBuffer]\n\tif block.Header == nil {\n\t\treturn errors.New(\"missing block header\")\n\t}\n\tif block.Data == nil {\n\t\treturn errors.New(\"missing block data\")\n\t}\n\tseq := block.Header.Number\n\tdataHash, err := protoutil.BlockDataHash(block.Data)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// Verify data hash matches the hash in the header\n\tif !bytes.Equal(dataHash, block.Header.DataHash) {\n\t\tcomputedHash := hex.EncodeToString(dataHash)\n\t\tclaimedHash := hex.EncodeToString(block.Header.DataHash)\n\t\treturn errors.Errorf(\"computed hash of block (%d) (%s) doesn't match claimed hash (%s)\",","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/util.go#L202-L238","documentation":"VerifyBlockHash was asked to verify the hash chain of a block whose index exceeds the number of blocks actually present in the supplied buffer. The caller passed an indexInBuffer that points past the end of blockBuff, so verification cannot proceed. It is a caller/programming or truncation error, not block corruption.","triggerScenarios":"Calling VerifyBlockHash(indexInBuffer, blockBuff) where len(blockBuff) <= indexInBuffer — e.g. verifying the last block in a sequence using a buffer that was truncated by an earlier failure or by pull of fewer blocks than expected.","commonSituations":"Block pulling/replication between Raft orderers where the delivered buffer is shorter than the sequence being verified; off-by-one in caller code computing the index of a block in a partial buffer.","solutions":["Ensure the caller computes indexInBuffer as the block's position within the same buffer it passes (typically the last index: len(blockBuff)-1).","Check upstream code (verifyBlockSequence / BlockPuller) for early returns that shrink blockBuff while continuing to verify at the original index.","If the buffer is genuinely short, re-pull the missing blocks from the source orderer before verifying."],"exampleFix":"// before\nerr := cluster.VerifyBlockHash(seq, buffer) // seq is chain-height index\n// after\nif len(buffer) == 0 || seq < buffer[0].Header.Number || int(seq-buffer[0].Header.Number) >= len(buffer) {\n    return errors.New(\"block not present in buffer\")\n}\nerr := cluster.VerifyBlockHash(int(seq-buffer[0].Header.Number), buffer)","handlingStrategy":"validation","validationCode":"func canVerify(indexInBuffer int, blockBuff []*common.Block) bool {\n    return indexInBuffer >= 0 && indexInBuffer < len(blockBuff)\n}\nif canVerify(idx, buff) {\n    err := cluster.VerifyBlockHash(idx, buff)\n}","typeGuard":"func blockAt(buff []*common.Block, i int) (*common.Block, bool) {\n    if i < 0 || i >= len(buff) || buff[i] == nil {\n        return nil, false\n    }\n    return buff[i], true\n}","tryCatchPattern":null,"preventionTips":["Always derive indexInBuffer from the same buffer you pass (e.g. len(buff)-1 or seq - buff[0].Header.Number).","Re-pull missing blocks instead of verifying against a truncated buffer.","Add unit tests around partial-buffer scenarios like TestVerifyBlockHash."],"tags":["blockchain","block-verification","index-out-of-bounds"],"backgroundTag":"index-out-of-bounds","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}