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

Manual block production is not allowed with trigger `Open`

Error message

Manual block production is not allowed with trigger `Open`

What it means

produce_manual_blocks rejects every manual request while the node runs Trigger::Open. With Open, block production stays open for `period` seconds and the block is only finalized when the period elapses, so the manual request cannot be resolved immediately as SharedState::manually_produce_block's oneshot caller expects. The guard is an explicit config-combination check, not a runtime failure.

Source

Thrown at crates/services/consensus_module/poa/src/service.rs:337

        deadline: Instant,
    ) -> anyhow::Result<()> {
        self.produce_block(
            self.next_height(),
            self.next_time(RequestType::Trigger)?,
            TransactionsSource::TxPool,
            deadline,
        )
        .await
    }

    async fn produce_manual_blocks(
        &mut self,
        block_production: ManualProduction,
    ) -> anyhow::Result<()> {
        // The caller of manual block production expects that it is resolved immediately
        // while in the case of `Trigger::Open` we need to wait for the period to pass.
        if matches!(self.trigger, Trigger::Open { .. }) {
            return Err(anyhow!(
                "Manual block production is not allowed with trigger `Open`"
            ))
        }

        let mut block_time = if let Some(time) = block_production.start_time {
            time
        } else {
            self.next_time(RequestType::Manual)?
        };
        match block_production.mode {
            Mode::Blocks { number_of_blocks } => {
                for _ in 0..number_of_blocks {
                    self.produce_block(
                        self.next_height(),
                        block_time,
                        TransactionsSource::TxPool,
                        Instant::now(),
                    )

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Switch the node's trigger to Trigger::Interval { block_time } or Trigger::Instant in the PoA config when tests/tooling need manual production.
  2. Do not call manually_produce_block against Open-configured nodes; wait for the open period to close the block instead.
  3. Gate the call up front: check the configured Trigger before sending a Request::ManualBlocks.

Example fix

// before
let config = Config {
    trigger: Trigger::Open { period: Duration::from_secs(5) },
    ..Default::default()
};
// ...
shared_state.manually_produce_block(None, Mode::Blocks { number_of_blocks: 1 }).await?; // Err

// after
let config = Config {
    trigger: Trigger::Interval { block_time: Duration::from_secs(5) },
    ..Default::default()
};
// ...
shared_state.manually_produce_block(None, Mode::Blocks { number_of_blocks: 1 }).await?; // Ok
Defensive patterns

Strategy: validation

Validate before calling

// Check before sending the manual request
fn manual_production_allowed(trigger: &fuel_core_poa::Trigger) -> bool {
    !matches!(trigger, fuel_core_poa::Trigger::Open { .. })
}

if !manual_production_allowed(&config.trigger) {
    anyhow::bail!("node uses Trigger::Open; manual block production is rejected");
}
shared_state.manually_produce_block(start_time, mode).await?;

Try / catch

match shared_state.manually_produce_block(start_time, mode).await {
    Err(err) if err.to_string().contains("Manual block production is not allowed") => {
        // config bug: switch trigger to Interval/Instant or wait for the open period
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling SharedState::manually_produce_block(start_time, Mode::Blocks{..} | Mode::BlockWithTransactions(..)) on a node whose Config.trigger is Trigger::Open { period } (crates/services/consensus_module/poa/src/service.rs:336). Typical in integration tests that reuse an Open-configured Service and then force blocks.

Common situations: Test harnesses configured for Trigger::Open (e.g. testing pre-confirmation flows) that also call manual production helpers; config migrated from Interval to Open while old test code still forces blocks; newer fuel-core versions where Trigger::Open was introduced and tests were not updated.

Related errors


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