FuelLabs/fuel-core · error
Run out of slots for the contract outputs
Error message
Run out of slots for the contract outputs
What it means
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.
Source
Thrown at crates/fuel-core/src/schema/tx/assemble_tx.rs:889
Default::default(),
contract_id,
));
let slot = self
.index_of_first_fake_variable_output
.and_then(|index| script.outputs_mut().get_mut(index as usize));
if let Some(slot) = slot {
*slot = Output::contract(
contract_idx,
Default::default(),
Default::default(),
);
self.index_of_first_fake_variable_output = self
.index_of_first_fake_variable_output
.and_then(|index| index.checked_add(1));
} else {
return Err(anyhow::anyhow!(
"Run out of slots for the contract outputs"
));
}
}
}
Ok((script, status))
}
async fn cover_fee(mut self) -> anyhow::Result<Self> {
let base_asset_id = *self.arguments.consensus_parameters.base_asset_id();
let gas_costs = self.arguments.consensus_parameters.gas_costs().clone();
let fee_params = *self.arguments.consensus_parameters.fee_params();
let max_gas_per_tx = self
.arguments
.consensus_parameters
.tx_params()
.max_gas_per_tx();View on GitHub (pinned to b9d4d170da)
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
Example fix
// before
script.outputs_mut().clear();
script.outputs_mut().push(Output::Variable::default()); // but script does 3 contract calls emitting values
// after
script.outputs_mut().clear();
for _ in 0..3 {
script.outputs_mut().push(Output::Variable::default()); // one slot per emitting call
} Defensive patterns
Strategy: validation
Validate before calling
// worst case: one Variable output per contract call that emits a value
const emittingCalls = countContractCallSites(scriptBytecode); // or track from your contract ABI
const variableOutputs = tx.outputs.filter(o => o.type === 'Variable').length;
if (variableOutputs < emittingCalls) {
throw new Error(`need ${emittingCalls} Variable outputs, tx has ${variableOutputs}`);
} Type guard
function hasEnoughVariableOutputs(tx: { outputs: Array<{ type: string }> }, needed: number): boolean {
return tx.outputs.filter(o => o.type === 'Variable').length >= needed;
} Try / catch
catch (e) { if (/Run out of slots for the contract outputs/.test(e.message)) { /* append Output::Variable entries and retry */ } else throw e; } Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- During script gas limit estimation, dry-run returned incorre
- missing contract id
- The transaction estimation requires running of predicate mor
- estimated predicates count overflow
- dry run count overflow
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/7453f6e63c58707b.
Report an issue: GitHub.