FuelLabs/fuel-core · error · anyhow::Error

The block production is disabled

Error message

The block production is disabled

What it means

PoAAdapter wraps Option<SharedState>; the PoA service (and its shared state) is only constructed when block production is enabled (sub_services.rs:423-448: `production_enabled.then(...)`). With shared_state == None, manually_produce_blocks refuses immediately — manual production requires a running producer loop to interact with.

Source

Thrown at crates/fuel-core/src/service/adapters/consensus_module/poa.rs:1241

    /// A block at this height already exists in the stream.
    HeightExists,
    /// Lock lost or epoch is stale — another leader holds the lock.
    FencingRejected,
}

impl PoAAdapter {
    pub fn new(shared_state: Option<SharedState>) -> Self {
        Self { shared_state }
    }

    pub async fn manually_produce_blocks(
        &self,
        start_time: Option<Tai64>,
        mode: Mode,
    ) -> anyhow::Result<()> {
        self.shared_state
            .as_ref()
            .ok_or(anyhow!("The block production is disabled"))?
            .manually_produce_block(start_time, mode)
            .await
    }
}

#[async_trait::async_trait]
impl BlockReconciliationReadPort for NoopReconciliationAdapter {
    async fn leader_state(
        &self,
        _next_height: BlockHeight,
    ) -> anyhow::Result<LeaderState> {
        Ok(LeaderState::ReconciledLeader)
    }

    async fn release(&self) -> anyhow::Result<()> {
        Ok(())
    }
}

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Start the node with block production enabled (dev/production consensus config) so SharedState exists.
  2. Only invoke manual production on nodes actually configured as producers.
  3. In tests/harnesses, construct the adapter with PoAAdapter::new(Some(shared_state)).

Example fix

// before
let adapter = PoAAdapter::new(None); // production disabled
adapter.manually_produce_blocks(None, mode).await?; // always errors

// after — enable production so the PoA service (and SharedState) is built
// (node config: enable block production), then:
let adapter = PoAAdapter::new(Some(shared_state));
adapter.manually_produce_blocks(None, mode).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Before calling manually_produce_blocks, confirm the node actually runs
// block production (PoA service was constructed) — e.g. reflect your config:
fn block_production_enabled(cfg: &Config) -> bool {
    cfg.consensus_key_config.is_some() /* or your production flag */
}
if !block_production_enabled(&config) {
    anyhow::bail!("refusing manual production: node is not a producer");
}

Try / catch

// If surfaced via an API layer, map to a clear client error:
if let Err(e) = result {
    if e.to_string().contains("block production is disabled") {
        return Err(anyhow!("this node is not configured for block production"));
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling manually_produce_blocks (e.g. a dev/GraphQL block-production trigger) on a node whose PoA service was never created because block production is disabled in its configuration.

Common situations: Running a plain non-producing node (regular validator/follower) and trying to trigger manual production; disabling production in config while keeping dev tooling enabled; test harnesses constructing PoAAdapter::new(None).

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/0b5c56238f5e8fe7. Report an issue: GitHub.