{"record":{"id":"b974343f70375947","repo":"FuelLabs/fuel-core","slug":"the-transaction-has-more-outputs-than-allowed-by-t","errorCode":null,"errorMessage":"The transaction has more outputs than allowed by the consensus","messagePattern":"The transaction has more outputs than allowed by the consensus","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fuel-core/src/schema/tx/assemble_tx.rs","lineNumber":185,"sourceCode":"    dry_run_count: usize,\n}\n\nimpl<'a, Tx> AssembleTx<'a, Tx>\nwhere\n    Tx: ExecutableTransaction + Cacheable + Send + 'static,\n{\n    pub fn new(tx: Tx, mut arguments: AssembleArguments<'a>) -> anyhow::Result<Self> {\n        let max_inputs = arguments.consensus_parameters.tx_params().max_inputs();\n        let max_outputs = arguments.consensus_parameters.tx_params().max_outputs();\n\n        if tx.inputs().len() > max_inputs as usize {\n            return Err(anyhow::anyhow!(\n                \"The transaction has more inputs than allowed by the consensus\"\n            ));\n        }\n\n        if tx.outputs().len() > max_outputs as usize {\n            return Err(anyhow::anyhow!(\n                \"The transaction has more outputs than allowed by the consensus\"\n            ));\n        }\n\n        if arguments.fee_index as usize >= arguments.required_balances.len() {\n            return Err(anyhow::anyhow!(\"The fee address index is out of bounds\"));\n        }\n\n        if has_duplicates(&arguments.required_balances, |balance| {\n            (balance.asset_id, balance.account.owner())\n        }) {\n            return Err(anyhow::anyhow!(\n                \"required balances contain duplicate (asset, account) pair\"\n            ));\n        }\n\n        let base_asset_id = *arguments.consensus_parameters.base_asset_id();\n        let mut signature_witness_indexes = HashMap::<Address, u16>::new();","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/fuel-core/src/schema/tx/assemble_tx.rs#L167-L203","documentation":"Thrown by the transaction assembler (the assembleTransaction GraphQL mutation, crates/fuel-core/src/schema/tx.rs) when the transaction bytes you submitted already contain more outputs than the chain allows. The limit comes from consensus parameters (tx_params.max_outputs), and AssembleTx::new rejects the transaction before doing any coin selection, fee estimation, or witness insertion.","triggerScenarios":"Calling assembleTransaction with a transaction whose outputs array length exceeds tx_params.max_outputs (commonly 255). The initial tx you encode (script with pre-declared Variable/Change outputs, or a batch of transfers) already violates the limit before assembly adds anything.","commonSituations":"Batching many transfers into one tx; scripts declaring one Variable output per expected contract call; operating a chain with a lowered max_outputs consensus parameter; chains after a consensus-parameter upgrade with tighter limits.","solutions":["Reduce the outputs in the submitted transaction: split into multiple transactions or drop unnecessary Change/Variable outputs (the assembler adds Change outputs itself)","Query chainInfo.consensusParameters.txParameters.maxOutputs and assert your decoded tx's outputs length is under it before calling assembleTransaction","If you operate the chain, raise max_outputs via a consensus parameter change"],"exampleFix":"// before\nconst res = await client.assembleTx(txBytes, { requiredBalances }); // tx has 300 outputs, node limit 255\n\n// after\nconst max = chainInfo.consensusParameters.txParameters.maxOutputs; // 255\nconst tx = Transaction.fromBytes(txBytes);\nwhile (tx.outputs.length > max) {\n  tx.outputs.pop(); // or split into several transactions\n}\nconst res = await client.assembleTx(tx.toBytes(), { requiredBalances });","handlingStrategy":"validation","validationCode":"const info = await client.request(gql`{ chain { consensusParameters { txParameters { maxOutputs } } } }`);\nconst maxOutputs = Number(info.chain.consensusParameters.txParameters.maxOutputs);\nconst tx = Transaction.fromBytes(txBytes);\nif (tx.outputs.length > maxOutputs) {\n  throw new Error(`outputs ${tx.outputs.length} > maxOutputs ${maxOutputs}`);\n}\nawait client.request(ASSEMBLE_TX, { tx: hexlify(txBytes), requiredBalances });","typeGuard":"function withinOutputLimit(decodedTx: { outputs: unknown[] }, maxOutputs: number): boolean {\n  return decodedTx.outputs.length <= maxOutputs;\n}","tryCatchPattern":"catch (e) { if (/more outputs than allowed by the consensus/.test(e.message)) { /* trim outputs and resubmit */ } else throw e; }","preventionTips":["Fetch maxOutputs from chainInfo at startup and assert on every tx you build","Let the assembler create Change outputs instead of pre-attaching them","Split large batches into several transactions"],"tags":["transaction","consensus","outputs","graphql","assemble-tx"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}