FuelLabs/fuel-core · critical
unable to produce blocks without a signer
Error message
unable to produce blocks without a signer
What it means
produce_predefined_block — the path that re-executes blocks yielded by the PredefinedBlocks port — checks self.signer.is_available() first, mirroring produce_block. Predefined blocks still need a signature over the produced header, so without a loaded consensus key the predefined-block production loop fails and the node cannot reproduce its scripted chain.
Source
Thrown at crates/services/consensus_module/poa/src/service.rs:446
// Update last block time
self.last_height = height;
self.last_timestamp = block_time;
self.last_block_created = match self.trigger {
Trigger::Open { .. } => deadline.max(last_block_created),
_ => last_block_created,
};
Ok(())
}
async fn produce_predefined_block(
&mut self,
predefined_block: &Block,
) -> anyhow::Result<()> {
tracing::info!("Producing predefined block");
let last_block_created = Instant::now();
if !self.signer.is_available() {
return Err(anyhow!("unable to produce blocks without a signer"))
}
// Ask the block producer to create the block
let (
ExecutionResult {
block,
skipped_transactions,
tx_status,
events,
},
changes,
) = self
.block_producer
.produce_predefined_block(predefined_block)
.await?
.into();
if !skipped_transactions.is_empty() {View on GitHub (pinned to b9d4d170da)
Solutions
- Set consensus_signer / Config.signer to SignMode::Key(secret) for any node that produces predefined blocks.
- Disable the predefined blocks source if this node should not reproduce the scripted chain.
- Assert signer.is_available() at startup before the predefined-blocks service begins.
Example fix
// before
let config = Config {
signer: SignMode::Unavailable,
..Default::default()
};
// after
let config = Config {
signer: SignMode::Key(Secret::new(predefined_chain_key.into())),
..Default::default()
}; Defensive patterns
Strategy: validation
Validate before calling
// Precondition for any predefined-block node
use fuel_core_types::signer::SignMode;
fn assert_predefined_blocks_signable(signer: &SignMode, has_predefined_blocks: bool) -> anyhow::Result<()> {
if has_predefined_blocks && !matches!(signer, SignMode::Key(_)) {
anyhow::bail!("predefined block production requires an available signer");
}
Ok(())
} Type guard
fn can_sign(signer: &SignMode) -> bool {
matches!(signer, SignMode::Key(_))
} Try / catch
// Service-level error: log and halt the predefined-blocks flow rather than looping
if let Err(err) = run_predefined_blocks(&mut task).await {
if err.to_string().contains("without a signer") {
tracing::error!("consensus key missing; predefined-block chain halted");
return Err(err);
}
return Err(err);
} Prevention
- Provision the consensus key before enabling a predefined-blocks chain.
- Assert signer.is_available() in node startup for any config where PredefinedBlocks can yield blocks.
- Keep the predefined-chain key in the same provisioning pipeline as other validator secrets.
When it happens
Trigger: A node configured with predefined blocks (PB: PredefinedBlocks returning blocks, e.g. deterministic test chains) whose signer is SignMode::Unavailable when the predefined block production round starts.
Common situations: Test/dev chain configs enabling predefined blocks while overriding consensus_signer to Unavailable; provisioning scripts that start predefined-block nodes before the key is available; forking test setups where the signer field was removed from Config.
Related errors
- unable to produce blocks without a consensus key
- Block production timed out
- Manual block production is not allowed with trigger `Open`
- The block timestamp should monotonically increase
- Time exceeds system limits
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/5eb22f97efc9e9c7.
Report an issue: GitHub.