linera-io/linera-protocol · error · ChainError
Signatures in a certificate must form a quorum
Error message
Signatures in a certificate must form a quorum
What it means
Thrown by check_signatures when the summed voting weight of a certificate's signers is below the committee's quorum threshold (ChainError::CertificateRequiresQuorum). Even if every individual signature is valid, a certificate is only meaningful if it proves agreement of a quorum (by voting weight) of the committee. The check runs after per-validator membership checks and before batch signature verification.
Source
Thrown at linera-chain/src/data_types/mod.rs:1160
signatures: &[(ValidatorPublicKey, ValidatorSignature)],
committee: &Committee,
) -> Result<(), ChainError> {
// Check the quorum.
let mut weight = 0;
let mut used_validators = HashSet::new();
for (validator, _) in signatures {
// Check that each validator only appears once.
ensure!(
!used_validators.contains(validator),
ChainError::CertificateValidatorReuse
);
used_validators.insert(*validator);
// Update weight.
let voting_rights = committee.weight(validator);
ensure!(voting_rights > 0, ChainError::InvalidSigner);
weight += voting_rights;
}
ensure!(
weight >= committee.quorum_threshold(),
ChainError::CertificateRequiresQuorum
);
// All that is left is checking signatures!
ValidatorSignature::verify_batch(value, signatures.iter())?;
Ok(())
}
impl BcsSignable<'_> for ProposalContent {}
impl BcsSignable<'_> for VoteValue {}
doc_scalar!(
MessageAction,
"Whether an incoming message is accepted or rejected."
);
#[cfg(test)]View on GitHub (pinned to 6c226ddcb3)
Solutions
- Ensure the certificate is only used after the aggregator reached quorum — SignatureAggregator::append returns Some(cert) exactly when the threshold is met.
- Recollect the missing signatures from validators until quorum before verifying.
- Verify against the committee (epoch) that produced the certificate, so the threshold matches the signing set.
- If weight was lost to deduplication, confirm the removed entries really were duplicates and not distinct validators.
Example fix
// before
let cert = aggregator.partial_clone_hack(); // partial, below quorum
check_signatures(&value, &cert.signatures, &committee)?;
// after
let mut aggregator = SignatureAggregator::new(value, round, unlocking, first_round, commitment, &committee);
let cert = loop {
let (key, sig) = receive_vote().await?;
if let Some(cert) = aggregator.append(key, sig)? {
break cert; // quorum reached
}
}; Defensive patterns
Strategy: retry
Validate before calling
let weight: u64 = signatures.iter().map(|(k, _)| committee.weight(k)).sum();
if weight < committee.quorum_threshold() {
return Err(anyhow::anyhow!(
"insufficient voting weight: {}/{}",
weight,
committee.quorum_threshold()
));
} Try / catch
match check_signatures(&value, &signatures, committee) {
Err(ChainError::CertificateRequiresQuorum) => {
// collect more signatures from remaining validators, then retry
collect_missing_signatures(&mut signatures, committee).await?;
check_signatures(&value, &signatures, committee)
}
other => other,
} Prevention
- Only circulate a certificate after SignatureAggregator::append returns Some.
- Track accumulated weight while collecting votes and request more before verification.
- Verify against the producing epoch's committee so thresholds match.
When it happens
Trigger: Verifying a certificate whose signature set aggregates less than committee.quorum_threshold() voting weight — e.g. a partial certificate captured before quorum was reached, a certificate checked against a larger committee than the one that signed it, or signatures pruned/lost in transit.
Common situations: Persisting or forwarding a partial (non-final) certificate from SignatureAggregator (append returned None and the partial state leaked); committee enlargement between epochs raising the threshold; network paths dropping some signatures; tests using too few validator keys.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Signatures in a certificate must be from different validator
- The signature was not created by a valid entity
- JustificationCommitmentMismatch
- Unexpected quorum: validators voted for block hash {hash} in
- InvalidCommitteeEpoch
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/c8b9930596eb81be.
Report an issue: GitHub.