datahaven-xyz/datahaven · error · Error

SyncCommitteeParticipantsNotSupermajority

SyncCommitteeParticipantsNotSupermajority

Error message

SyncCommitteeParticipantsNotSupermajority

What it means

Thrown by `sync_committee_participation_is_supermajority` when the sync-aggregate bitfield has fewer than 2/3 of its bits set. Ethereum consensus requires a 2/3 supermajority of sync committee participants for an update signature to be valid; without it the attestation cannot be trusted.

Solutions

  1. Wait for and submit a later update with ≥2/3 participation; finalized updates typically have near-full participation.
  2. Verify the relayer does not truncate or corrupt the `sync_committee_bits` bitfield during serialization.
  3. Check beacon chain finality health; prolonged low participation indicates upstream liveness issues.
  4. Re-fetch the aggregate from a full node rather than a cached/derived copy.

Example fix

// before: submit any fetched update
submit(update);
// after: pre-check participation on the relayer
let bits = count_bits(update.sync_aggregate.sync_committee_bits);
require!(bits * 3 >= SYNC_COMMITTEE_SIZE * 2);
submit(update);
Defensive patterns

Strategy: validation

Validate before calling

const sum = countBits(update.sync_aggregate.sync_committee_bits);
if (sum * 3 < SYNC_COMMITTEE_SIZE * 2) {
  throw new Error('sync aggregate lacks 2/3 supermajority');
}

Type guard

function hasSupermajority(bits, committeeSize) {
  return bits.reduce((a, b) => a + b, 0) * 3 >= committeeSize * 2;
}

Try / catch

try {
  await submit(update);
} catch (e) {
  if (String(e).includes('SyncCommitteeParticipantsNotSupermajority')) {
    await waitForNextUpdateWithFullParticipation();
  }
}

Prevention

When it happens

Trigger: Submitting a light-client update whose `sync_aggregate.sync_committee_bits` produce `sync_committee_sum * 3 < bits.len() * 2` — i.e. a weakly signed update from the beacon chain.

Common situations: Replaying an update that was later superseded by one with higher participation, relayer picking malformed/edge-case aggregates, or an actual network liveness problem on the beacon chain.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of datahaven-xyz/datahaven@edcb13dbbc (2026-09-13). Data as JSON: /api/errors/50ccf3bbc29a6698. Report an issue: GitHub.

Appendix: source

Thrown at operator/pallets/ethereum-client/src/lib.rs:637

        ) -> Result<H256, DispatchError> {
            let hash_root = ForkData {
                current_version,
                genesis_validators_root: genesis_validators_root.into(),
            }
            .hash_tree_root()
            .map_err(|_| Error::<T>::ForkDataHashTreeRootFailed)?;

            Ok(hash_root)
        }

        /// Checks that the sync committee bits (the votes of the sync committee members,
        /// represented by bits 0 and 1) is more than a supermajority (2/3 of the votes are
        /// positive).
        pub(super) fn sync_committee_participation_is_supermajority(
            sync_committee_bits: &[u8],
        ) -> DispatchResult {
            let sync_committee_sum = sync_committee_sum(sync_committee_bits);
            ensure!(
                ((sync_committee_sum * 3) as usize) >= sync_committee_bits.len() * 2,
                Error::<T>::SyncCommitteeParticipantsNotSupermajority
            );

            Ok(())
        }

        /// Returns the fork version based on the current epoch. The hard fork versions
        /// are defined in pallet config.
        pub(super) fn compute_fork_version(epoch: u64) -> ForkVersion {
            Self::select_fork_version(&T::ForkVersions::get(), epoch)
        }

        /// Returns the fork version based on the current epoch.
        pub(super) fn select_fork_version(fork_versions: &ForkVersions, epoch: u64) -> ForkVersion {
            if epoch >= fork_versions.fulu.epoch {
                return fork_versions.fulu.version;
            }

View on GitHub (pinned to edcb13dbbc)