{"record":{"id":"8131a6403595e288","repo":"hyperledger/fabric","slug":"block-has-only-d-transactions-but-requested-tx-a","errorCode":null,"errorMessage":"block has only %d transactions, but requested tx at position %d","messagePattern":"block has only (.+?) transactions, but requested tx at position (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/handlers/validation/builtin/default_validation.go","lineNumber":61,"sourceCode":"//go:generate mockery -dir . -name TransactionValidator -case underscore -output mocks/\ntype TransactionValidator interface {\n\tValidate(block *common.Block, namespace string, txPosition int, actionPosition int, policy []byte) commonerrors.TxValidationError\n}\n\nfunc (v *DefaultValidation) Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...validation.ContextDatum) error {\n\tif len(contextData) == 0 {\n\t\tlogger.Panicf(\"Expected to receive policy bytes in context data\")\n\t}\n\n\tserializedPolicy, isSerializedPolicy := contextData[0].(vp.SerializedPolicy)\n\tif !isSerializedPolicy {\n\t\tlogger.Panicf(\"Expected to receive a serialized policy in the first context data\")\n\t}\n\tif block == nil || block.Data == nil {\n\t\treturn errors.New(\"empty block\")\n\t}\n\tif txPosition >= len(block.Data.Data) {\n\t\treturn errors.Errorf(\"block has only %d transactions, but requested tx at position %d\", len(block.Data.Data), txPosition)\n\t}\n\tif block.Header == nil {\n\t\treturn errors.Errorf(\"no block header\")\n\t}\n\n\tvar err error\n\tswitch {\n\tcase v.Capabilities.V2_0Validation():\n\t\terr = v.TxValidatorV2_0.Validate(block, namespace, txPosition, actionPosition, serializedPolicy.Bytes())\n\n\tcase v.Capabilities.V1_3Validation():\n\t\terr = v.TxValidatorV1_3.Validate(block, namespace, txPosition, actionPosition, serializedPolicy.Bytes())\n\n\tcase v.Capabilities.V1_2Validation():\n\t\tfallthrough\n\n\tdefault:\n\t\terr = v.TxValidatorV1_2.Validate(block, namespace, txPosition, actionPosition, serializedPolicy.Bytes())","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/handlers/validation/builtin/default_validation.go#L43-L79","documentation":"During commit-time validation, the builtin plugin validates the transaction at txPosition within block.Data.Data. This error is returned when the requested transaction index is out of range: the block contains fewer transactions than the requested position, indicating a miscomputed index by the caller or a truncated block.","triggerScenarios":"Validate (committer path, TestErrorConversion, TestValidateBadInput) receives txPosition >= len(block.Data.Data), e.g. the committer computes the tx index from metadata that disagrees with the block's actual envelope count, or tests pass an index beyond a small fixture block.","commonSituations":"Truncated/corrupted block file on disk so Data has fewer envelopes than metadata claims; off-by-one in a custom committer or test; block produced by a misbehaving ordering node.","solutions":["Compare the block's metadata vs Data.Data length in the log to find who supplied the bad index","Check block storage integrity; if corrupted, rebuild the ledger database or resync from an orderer/other peer","Fix custom committer/test code to bounds-check txPosition before Validate","Verify all ordering nodes run compatible Fabric versions producing consistent block structure"],"exampleFix":"// before: index taken from metadata without bounds check\ntxPos := int(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER][0])\nerr := v.Validate(block, ns, txPos, 0, policy) // index may exceed len(Data.Data)\n// after\nif txPos < 0 || txPos >= len(block.Data.Data) {\n    return fmt.Errorf(\"invalid tx position %d\", txPos)\n}\nerr := v.Validate(block, ns, txPos, 0, policy)","handlingStrategy":"validation","validationCode":"if txPosition < 0 || txPosition >= len(block.Data.Data) {\n    return fmt.Errorf(\"tx position %d out of range, block has %d txs\", txPosition, len(block.Data.Data))\n}\nerr := validator.Validate(block, namespace, txPosition, actionPosition, policyBytes)","typeGuard":"func txIndexValid(b *common.Block, pos int) bool {\n    return b != nil && b.Data != nil && pos >= 0 && pos < len(b.Data.Data)\n}","tryCatchPattern":"err := v.Validate(block, ns, txPos, actionPos, policy)\nif err != nil && strings.HasPrefix(err.Error(), \"block has only\") {\n    logger.Errorf(\"tx index out of range; verify committer index and block integrity: %v\", err)\n    return err\n}","preventionTips":["Bounds-check txPosition derived from block metadata","Detect truncated blocks by comparing envelope counts with metadata","Keep orderer and peer Fabric versions compatible","Resync from peers/orderers if block files are corrupted"],"tags":["fabric","validation-plugin","block-validation","index-out-of-range","committer"],"backgroundTag":"transaction-index-out-of-range","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"}