{"record":{"id":"2bf40f4f5f65420a","repo":"FuelLabs/fuel-core","slug":"cannot-publish-block-because-fencing-token-is-not","errorCode":null,"errorMessage":"Cannot publish block because fencing token is not initialized","messagePattern":"Cannot publish block because fencing token is not initialized","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/fuel-core/src/service/adapters/consensus_module/poa.rs","lineNumber":1372,"sourceCode":"impl BlockReconciliationWritePort for RedisLeaderLeaseAdapter {\n    fn publish_produced_block(&self, block: &SealedBlock) -> anyhow::Result<()> {\n        let epoch = match *self\n            .current_epoch_token\n            .lock()\n            .map_err(|_| anyhow!(\"cannot access epoch token, poisoned lock\"))?\n        {\n            Some(epoch) => epoch,\n            None => {\n                if matches!(\n                    block.consensus,\n                    fuel_core_types::blockchain::consensus::Consensus::Genesis(_)\n                ) {\n                    tracing::debug!(\n                        \"Skipping redis block publish for genesis block because fencing token is not initialized\"\n                    );\n                    return Ok(());\n                }\n                return Err(anyhow!(\n                    \"Cannot publish block because fencing token is not initialized\"\n                ));\n            }\n        };\n        let block_data = postcard::to_allocvec(block)?;\n        let successes = self\n            .publish_block_on_all_nodes(epoch, block, &block_data)\n            .into_iter()\n            .map(|result| match result {\n                Ok(WriteBlockResult::Written) => true,\n                Ok(_) => false,\n                Err(err) => {\n                    tracing::debug!(\"Redis publish on node failed: {err}\");\n                    false\n                }\n            })\n            .filter(|success| *success)\n            .count();","sourceCodeStart":1354,"sourceCodeEnd":1390,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/fuel-core/src/service/adapters/consensus_module/poa.rs#L1354-L1390","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before producing/publishing, ensure leadership was established at least\n// once this process lifetime:\nif !adapter.can_produce_block().await? {\n    anyhow::bail!(\"cannot publish: leader lease not acquired yet\");\n}\n// ... produce and publish","typeGuard":null,"tryCatchPattern":"// If it still fires, classify it distinctly — it indicates a sequencing bug:\nif let Err(e) = publish_result {\n    if e.to_string().contains(\"fencing token is not initialized\") {\n        tracing::error!(\"BUG: publish attempted before lease acquisition\");\n    }\n    return Err(e);\n}","preventionTips":["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."],"tags":["redis","lease","fencing","sequencing","block-production"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}