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

Cannot publish block because fencing token is not initialize

Error message

Cannot publish block because fencing token is not initialized

What it means

publish_produced_block requires a fencing epoch to stamp Redis writes; current_epoch_token is None (lease never acquired). Genesis blocks are deliberately skipped (they need no fencing), but any non-genesis block published before this node ever won the leader lease is rejected.

Source

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

impl BlockReconciliationWritePort for RedisLeaderLeaseAdapter {
    fn publish_produced_block(&self, block: &SealedBlock) -> anyhow::Result<()> {
        let epoch = match *self
            .current_epoch_token
            .lock()
            .map_err(|_| anyhow!("cannot access epoch token, poisoned lock"))?
        {
            Some(epoch) => epoch,
            None => {
                if matches!(
                    block.consensus,
                    fuel_core_types::blockchain::consensus::Consensus::Genesis(_)
                ) {
                    tracing::debug!(
                        "Skipping redis block publish for genesis block because fencing token is not initialized"
                    );
                    return Ok(());
                }
                return Err(anyhow!(
                    "Cannot publish block because fencing token is not initialized"
                ));
            }
        };
        let block_data = postcard::to_allocvec(block)?;
        let successes = self
            .publish_block_on_all_nodes(epoch, block, &block_data)
            .into_iter()
            .map(|result| match result {
                Ok(WriteBlockResult::Written) => true,
                Ok(_) => false,
                Err(err) => {
                    tracing::debug!("Redis publish on node failed: {err}");
                    false
                }
            })
            .filter(|success| *success)
            .count();

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Fix sequencing: only produce/publish after can_produce_block() returns true (lease acquired or held).
  2. If the block really is genesis, confirm its consensus is exactly Consensus::Genesis — only that variant is skipped.
  3. In tests, run one successful lease acquire before publishing to seed current_epoch_token.
Defensive patterns

Strategy: validation

Validate before calling

// Before producing/publishing, ensure leadership was established at least
// once this process lifetime:
if !adapter.can_produce_block().await? {
    anyhow::bail!("cannot publish: leader lease not acquired yet");
}
// ... produce and publish

Try / catch

// If it still fires, classify it distinctly — it indicates a sequencing bug:
if let Err(e) = publish_result {
    if e.to_string().contains("fencing token is not initialized") {
        tracing::error!("BUG: publish attempted before lease acquisition");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: The block production path reaches publish_produced_block with a non-Genesis block before acquire_lease_if_free has ever succeeded — e.g. production starts before leader election completes, or the reconciliation write port is exercised in a context that never took the lease.

Common situations: Race between producer startup and first lease acquisition; test setups that skip can_produce_block; a node whose lease acquisition persistently fails (Redis down) while blocks keep being produced.

Related errors


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