{"record":{"id":"863aae68a3549b43","repo":"datahaven-xyz/datahaven","slug":"invalidsynccommitteeupdate","errorCode":"InvalidSyncCommitteeUpdate","errorMessage":"InvalidSyncCommitteeUpdate","messagePattern":"InvalidSyncCommitteeUpdate","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"operator/pallets/ethereum-client/src/lib.rs","lineNumber":420,"sourceCode":"                    update.block_roots_root,\n                    &update.block_roots_branch,\n                    subtree_index(block_roots_gindex),\n                    generalized_index_length(block_roots_gindex),\n                    update.finalized_header.state_root\n                ),\n                Error::<T>::InvalidBlockRootsRootMerkleProof\n            );\n\n            // Verify that the `next_sync_committee`, if present, actually is the next sync\n            // committee saved in the state of the `attested_header`.\n            if let Some(next_sync_committee_update) = &update.next_sync_committee_update {\n                let sync_committee_root = next_sync_committee_update\n                    .next_sync_committee\n                    .hash_tree_root()\n                    .map_err(|_| Error::<T>::SyncCommitteeHashTreeRootFailed)?;\n                if update_attested_period == store_period && <NextSyncCommittee<T>>::exists() {\n                    let next_committee_root = <NextSyncCommittee<T>>::get().root;\n                    ensure!(\n                        sync_committee_root == next_committee_root,\n                        Error::<T>::InvalidSyncCommitteeUpdate\n                    );\n                }\n                let next_sync_committee_gindex = Self::next_sync_committee_gindex_at_slot(\n                    update.attested_header.slot,\n                    fork_versions,\n                );\n                ensure!(\n                    verify_merkle_branch(\n                        sync_committee_root,\n                        &next_sync_committee_update.next_sync_committee_branch,\n                        subtree_index(next_sync_committee_gindex),\n                        generalized_index_length(next_sync_committee_gindex),\n                        update.attested_header.state_root\n                    ),\n                    Error::<T>::InvalidSyncCommitteeMerkleProof\n                );","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/datahaven-xyz/datahaven/blob/edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec/operator/pallets/ethereum-client/src/lib.rs#L402-L438","documentation":"Thrown in `verify_update` when a submitted light-client update carries a `next_sync_committee` whose computed hash-tree root does not match the committee root already stored as `NextSyncCommittee` in the pallet (when attested period == store period and a next committee exists). The Ethereum consensus light-client protocol requires the proposed next sync committee to be identical to the one committed in the attested beacon state; any mismatch means the update is inconsistent with the on-chain store.","triggerScenarios":"Calling the update submission extrinsic (e.g. `submit_finality_update`-style entry that runs `verify_update`) with an update whose `next_sync_committee_update` root differs from `NextSyncCommittee::<T>::get().root` while `update_attested_period == store_period` and a next committee is already stored. Happens with stale, malformed, or fabricated sync-committee payloads.","commonSituations":"Relayer submitting updates from a different beacon network/fork, updating with data from an older period, corrupted serialization of the sync committee, or mixing bootstrap data from one chain deployment with updates from another.","solutions":["Re-fetch a fresh light-client update directly from a trusted beacon-node endpoint and re-submit it.","Verify the relayer is on the correct network (mainnet vs testnet/fork) and that fork version configuration `T::ForkVersions` matches the chain.","If the stored NextSyncCommittee is corrupt/stale, wait for a period-boundary update where `update_finalized_period == store_period + 1` to rotate the committee.","Confirm the update was built with the same spec (Altair/Capella+) that the pallet's hash-tree-root implementation expects."],"exampleFix":"// before: relayer cached an old update\nsubmit_update(stale_update);\n// after: always build the update from current beacon state\nlet update = beacon_client.get_light_client_update(finalized_slot);\nsubmit_update(update);","handlingStrategy":"validation","validationCode":"let stored_root = api.query.ethereumClient.nextSyncCommittee().root;\nlet update_root = hash_tree_root(update.next_sync_committee_update.next_sync_committee);\nif update_root !== stored_root { throw new Error('next sync committee does not match stored'); }","typeGuard":"function isCurrentPeriodUpdate(update, storePeriod) {\n  return computePeriod(update.attested_header.slot) === storePeriod;\n}","tryCatchPattern":"try {\n  await api.tx.ethereumClient.submitFinalityUpdate(update).signAndSend(signer);\n} catch (e) {\n  if (String(e).includes('InvalidSyncCommitteeUpdate')) {\n    console.error('Re-fetch update from beacon node; stored next committee mismatch');\n  }\n}","preventionTips":["Always build updates from a live trusted beacon node, never cache across restarts","Verify fork-version configuration matches the target chain before relaying","Log store_period and attested_period on the relayer before submission"],"tags":["blockchain","consensus","merkle-proof","validation"],"backgroundTag":"invalid-argument-value","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"}