{"record":{"id":"7453f6e63c58707b","repo":"FuelLabs/fuel-core","slug":"run-out-of-slots-for-the-contract-outputs","errorCode":null,"errorMessage":"Run out of slots for the contract outputs","messagePattern":"Run out of slots for the contract outputs","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fuel-core/src/schema/tx/assemble_tx.rs","lineNumber":889,"sourceCode":"                    Default::default(),\n                    contract_id,\n                ));\n\n                let slot = self\n                    .index_of_first_fake_variable_output\n                    .and_then(|index| script.outputs_mut().get_mut(index as usize));\n\n                if let Some(slot) = slot {\n                    *slot = Output::contract(\n                        contract_idx,\n                        Default::default(),\n                        Default::default(),\n                    );\n                    self.index_of_first_fake_variable_output = self\n                        .index_of_first_fake_variable_output\n                        .and_then(|index| index.checked_add(1));\n                } else {\n                    return Err(anyhow::anyhow!(\n                        \"Run out of slots for the contract outputs\"\n                    ));\n                }\n            }\n        }\n\n        Ok((script, status))\n    }\n\n    async fn cover_fee(mut self) -> anyhow::Result<Self> {\n        let base_asset_id = *self.arguments.consensus_parameters.base_asset_id();\n        let gas_costs = self.arguments.consensus_parameters.gas_costs().clone();\n        let fee_params = *self.arguments.consensus_parameters.fee_params();\n        let max_gas_per_tx = self\n            .arguments\n            .consensus_parameters\n            .tx_params()\n            .max_gas_per_tx();","sourceCodeStart":871,"sourceCodeEnd":907,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/fuel-core/src/schema/tx/assemble_tx.rs#L871-L907","documentation":"During gas estimation the assembler replaces the tx's fake Variable outputs (zeroed, used as placeholders) with real contract outputs as contract calls produce them. This error fires when a contract call produces an output but no fake Variable output slot remains to hold it.","triggerScenarios":"The script performs more output-producing contract calls than the number of Variable outputs declared in the tx (the assembler already consumed the earlier slots and index_of_first_fake_variable_output ran past the end of the outputs).","commonSituations":"Hand-written scripts with too few Variable outputs; SDK versions that stopped auto-adding variable outputs; loops in contract code emitting more values than the caller declared.","solutions":["Add enough Output::Variable entries to the script tx to cover every contract return that emits a value (one per call site iteration in the worst case)","Use a wallet/SDK that pads Variable outputs automatically before assembly","Restructure the contract interaction to return an aggregate value in one call instead of many"],"exampleFix":"// before\nscript.outputs_mut().clear();\nscript.outputs_mut().push(Output::Variable::default()); // but script does 3 contract calls emitting values\n\n// after\nscript.outputs_mut().clear();\nfor _ in 0..3 {\n  script.outputs_mut().push(Output::Variable::default()); // one slot per emitting call\n}","handlingStrategy":"validation","validationCode":"// worst case: one Variable output per contract call that emits a value\nconst emittingCalls = countContractCallSites(scriptBytecode); // or track from your contract ABI\nconst variableOutputs = tx.outputs.filter(o => o.type === 'Variable').length;\nif (variableOutputs < emittingCalls) {\n  throw new Error(`need ${emittingCalls} Variable outputs, tx has ${variableOutputs}`);\n}","typeGuard":"function hasEnoughVariableOutputs(tx: { outputs: Array<{ type: string }> }, needed: number): boolean {\n  return tx.outputs.filter(o => o.type === 'Variable').length >= needed;\n}","tryCatchPattern":"catch (e) { if (/Run out of slots for the contract outputs/.test(e.message)) { /* append Output::Variable entries and retry */ } else throw e; }","preventionTips":["Pad one Variable output per output-producing contract call, including loop iterations","Prefer a single aggregate return value over repeated emissions","Use SDK helpers that auto-add variable outputs before estimation"],"tags":["script","variable-output","contract","estimation","assemble-tx"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}