linera-io/linera-protocol · error · ChainError
The signature was not created by a valid entity
Error message
The signature was not created by a valid entity
What it means
Thrown by SignatureAggregator::append when the signature's public key has zero voting weight in the aggregator's committee, i.e. the signer is not a member of the current committee (ChainError::InvalidSigner). The aggregator only counts signatures from validators with voting rights in the committee it was constructed with. A signature from an unknown or retired validator can never contribute to the quorum, so append rejects it immediately.
Source
Thrown at linera-chain/src/data_types/mod.rs:1118
{
let hash_and_round = VoteValue(
self.partial.hash(),
self.partial.round,
T::KIND,
self.partial.unlocking_round(),
self.partial.first_round(),
self.partial.justification_commitment(),
);
signature.check(&hash_and_round, public_key)?;
// Check that each validator only appears once.
ensure!(
!self.used_validators.contains(&public_key),
ChainError::CertificateValidatorReuse
);
self.used_validators.insert(public_key);
// Update weight.
let voting_rights = self.committee.weight(&public_key);
ensure!(voting_rights > 0, ChainError::InvalidSigner);
self.weight += voting_rights;
// Update certificate.
self.partial.add_signature((public_key, signature));
if self.weight >= self.committee.quorum_threshold() {
self.weight = 0; // Prevent from creating the certificate twice.
Ok(Some(self.partial.clone()))
} else {
Ok(None)
}
}
}
// Checks if the array slice is strictly ordered. That means that if the array
// has duplicates, this will return False, even if the array is sorted
pub(crate) fn is_strictly_ordered(values: &[(ValidatorPublicKey, ValidatorSignature)]) -> bool {
values.windows(2).all(|pair| pair[0].0 < pair[1].0)
}View on GitHub (pinned to 6c226ddcb3)
Solutions
- Verify committee.weight(&public_key) > 0 before calling append, and skip/drop the vote when it is 0.
- Check that the aggregator and the votes come from the same epoch — rebuild the aggregator with the committee of the epoch the votes were cast in.
- If you aggregate votes received over the network, filter them against the current committee at receipt time so stale validators never reach the aggregator.
- In tests, make sure the signing keys are taken from the same Committee builder used to construct the aggregator.
Example fix
// before
for (key, sig) in votes {
if let Some(cert) = aggregator.append(key, sig)? {
return Ok(cert);
}
}
// after
for (key, sig) in votes {
if committee.weight(&key) == 0 {
continue; // not a member of this committee; skip
}
if let Some(cert) = aggregator.append(key, sig)? {
return Ok(cert);
}
} Defensive patterns
Strategy: validation
Validate before calling
// before aggregating a vote
if committee.weight(&public_key) == 0 {
tracing::warn!(?public_key, "dropping vote from non-committee validator");
continue;
} Try / catch
match aggregator.append(key, sig) {
Ok(Some(cert)) => return Ok(cert),
Ok(None) => {}
Err(ChainError::InvalidSigner) => continue, // skip non-committee voter
Err(e) => return Err(e),
} Prevention
- Always construct the SignatureAggregator with the committee of the epoch the votes belong to.
- Filter incoming votes by committee membership at receipt time.
- Log the offending public key to spot committee-configuration drift quickly.
When it happens
Trigger: Calling SignatureAggregator::append(public_key, signature) where committee.weight(&public_key) == 0. Happens when votes are collected from validators of a different epoch: e.g. a worker still holds votes signed under an old committee while the aggregator was built with the new one, or the operator feed maps a stale validator key set to a new committee.
Common situations: Epoch/committee rotations where in-flight votes from the outgoing committee reach the aggregator of the incoming one; misconfigured validator sets between nodes; test code generating signatures with keys never registered in the committee.
Related errors
- Signatures in a certificate must be from different validator
- Signatures in a certificate must form a quorum
- InvalidCommitteeEpoch
- no signer found for owner ${owner}
- Found issues while querying validators
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/2a9f624dde69019d.
Report an issue: GitHub.