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
- Fix sequencing: only produce/publish after can_produce_block() returns true (lease acquired or held).
- If the block really is genesis, confirm its consensus is exactly Consensus::Genesis — only that variant is skipped.
- 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
- Gate the producer on a successful lease acquisition before the first block.
- Genesis is the only block exempt — never rely on that exemption for real blocks.
- In tests, perform one acquire before any publish call.
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
- Cannot repair block because fencing token is not initialized
- Lost lock during repair — another leader took over
- Failed to publish block to redis quorum with fencing checks
- Failed to release lease on quorum
- Not implemented yet
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/2bf40f4f5f65420a.
Report an issue: GitHub.