{"record":{"id":"e9b73343e2596787","repo":"datahaven-xyz/datahaven","slug":"headernotfinalized","errorCode":"HeaderNotFinalized","errorMessage":"HeaderNotFinalized","messagePattern":"HeaderNotFinalized","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"operator/pallets/ethereum-client/src/impls.rs","lineNumber":81,"sourceCode":"                log::trace!(\n                    target: \"ethereum-client\",\n                    \"💫 Failed to decode transaction receipt: {}\",\n                    err\n                );\n                Err(InvalidProof)\n            }\n        }\n    }\n\n    /// Validates an execution header with ancestry_proof against a finalized checkpoint on\n    /// chain.The beacon header containing the execution header is sent, plus the execution header,\n    /// along with a proof that the execution header is rooted in the beacon header body.\n    pub(crate) fn verify_execution_proof(execution_proof: &ExecutionProof) -> DispatchResult {\n        let latest_finalized_state =\n            FinalizedBeaconState::<T>::get(LatestFinalizedBlockRoot::<T>::get())\n                .ok_or(Error::<T>::NotBootstrapped)?;\n        // Checks that the header is an ancestor of a finalized header, using slot number.\n        ensure!(\n            execution_proof.header.slot <= latest_finalized_state.slot,\n            Error::<T>::HeaderNotFinalized\n        );\n\n        let beacon_block_root: H256 = execution_proof\n            .header\n            .hash_tree_root()\n            .map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;\n\n        match &execution_proof.ancestry_proof {\n            Some(proof) => {\n                Self::verify_ancestry_proof(\n                    beacon_block_root,\n                    execution_proof.header.slot,\n                    &proof.header_branch,\n                    proof.finalized_block_root,\n                )?;\n            }","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/datahaven-xyz/datahaven/blob/edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec/operator/pallets/ethereum-client/src/impls.rs#L63-L99","documentation":"verify_execution_proof in the ethereum-client pallet checks that the supplied execution-layer header's slot does not exceed the slot of the latest finalized beacon state stored at LatestFinalizedBlockRoot. A header with a slot beyond that point cannot yet be proven as an ancestor of a finalized checkpoint, so the proof is rejected with HeaderNotFinalized. The pallet only accepts proofs for headers that are provably finalized.","triggerScenarios":"Submitting an execution proof (e.g. via submit_execution_proof / message-relay style extrinsics) whose execution header slot is greater than latest_finalized_state.slot — i.e., relaying a header that FinalizedBeaconState hasn't caught up to yet.","commonSituations":"Relayer racing ahead of the beacon finality updates (submitting proofs before the bootstrap/latest-finalized root is updated); the pallet not yet bootstrapped to a recent checkpoint; clock/slot arithmetic off between relayer and chain.","solutions":["Wait until the beacon client finalizes the target slot (update_finalized_beacon_state / checkpoint update) and resubmit the proof.","Verify the pallet is bootstrapped to a current checkpoint and that relayers follow finality, not just head.","Check the execution header slot against FinalizedBeaconState[LatestFinalizedBlockRoot].slot before submission."],"exampleFix":"// before: submit as soon as header is seen\nawait api.tx.ethereumClient.submitExecutionProof(proof).signAndSend(relayer);\n// after\nconst latestRoot = await api.query.ethereumClient.latestFinalizedBlockRoot();\nconst state = await api.query.ethereumClient.finalizedBeaconState(latestRoot);\nif (proof.header.slot > state.slot.toNumber()) throw new Error('header not yet finalized');\nawait api.tx.ethereumClient.submitExecutionProof(proof).signAndSend(relayer);","handlingStrategy":"retry","validationCode":"const latestRoot = await api.query.ethereumClient.latestFinalizedBlockRoot();\nconst state = await api.query.ethereumClient.finalizedBeaconState(latestRoot);\nif (!state.isSome) throw new Error('client not bootstrapped');\nif (proof.header.slot > state.value.slot.toNumber()) throw new Error('wait for finality: header slot beyond latest finalized state');","typeGuard":null,"tryCatchPattern":"try {\n  await api.tx.ethereumClient.submitExecutionProof(proof).signAndSend(relayer);\n} catch (e) {\n  if (String(e).includes('HeaderNotFinalized')) scheduleRetryAfterFinality(proof);\n  else throw e;\n}","preventionTips":["Relayers should track beacon finality checkpoints, not chain head.","Gate submissions on state.slot >= header.slot.","Bootstrap the light client to a recent checkpoint before operating.","Add backoff-based resubmission for proofs that are merely early."],"tags":["consensus","finality","beacon","light-client"],"backgroundTag":"invalid-state-transition","analyzedSha":"edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec","analyzedAt":"2026-09-13T19:19:32.206Z","contentChangedAt":"2026-09-13T19:19:32.206Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}