linera-io/linera-protocol · error · Error
MetaMask is not connected with the requested owner: ${owner}
Error message
MetaMask is not connected with the requested owner: ${owner} What it means
revoke_epochs builds an Admin operation that revokes all epochs up to and including revoked_epoch. The guard ensure!(revoked_epoch < current_epoch) rejects revoking the epoch the chain is currently in (or any future epoch): the current epoch's committee is still signing blocks, so revoking it would break consensus. Only strictly older epochs may be revoked.
Source
Thrown at web/@linera/metamask/src/signer.ts:57
async sign(owner: string, value: Uint8Array): Promise<string> {
if (!window.ethereum) {
throw new Error("MetaMask is not available");
}
// Explicitly type the result and check for undefined
const accounts = (await window.ethereum.request({
method: "eth_requestAccounts",
})) as string[] | undefined;
if (!accounts || accounts.length === 0) {
throw new Error("No MetaMask accounts connected");
}
const connected = accounts.find(
(acc) => acc.toLowerCase() === owner.toLowerCase(),
);
if (!connected) {
throw new Error(
`MetaMask is not connected with the requested owner: ${owner}`,
);
}
// Encode message as hex string
const msgHex = `0x${uint8ArrayToHex(value)}`;
try {
const signature = (await window.ethereum.request({
method: "personal_sign",
params: [msgHex, owner],
})) as string;
if (!signature) {
throw new Error("No signature returned");
}
return signature;
} catch (err: any) {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Pass an epoch strictly lower than the current one: use revoke_epochs(Epoch(current.0.saturating_sub(1))) at most, and only if current > 0.
- If you intend to retire the current committee, first create and migrate to a new epoch, then revoke the old one.
- Read the chain's current epoch via chain_info().epoch before constructing the call and validate the bound in your script.
- Check for off-by-one in loops: iterate 0..revoked_epoch.0 after validating revoked_epoch < current_epoch.
Example fix
// before: revoking the epoch the chain is still using
client.revoke_epochs(current_epoch).await?; // CannotRevokeCurrentEpoch
// after: revoke only strictly older epochs
let current = client.chain_info().await?.epoch;
if revoked_epoch < current {
client.revoke_epochs(revoked_epoch).await?;
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the epoch bound before revoking
let current = client.chain_info().await?.epoch;
if revoked_epoch >= current {
return Err(anyhow::anyhow!("can only revoke epochs < current ({current}); got {revoked_epoch}"));
} Type guard
pub async fn can_revoke_epoch(client: &ChainClient, epoch: Epoch) -> Result<bool, Error> {
Ok(epoch < client.chain_info().await?.epoch)
} Try / catch
match client.revoke_epochs(revoked_epoch).await {
Ok(outcome) => outcome,
Err(Error::CannotRevokeCurrentEpoch(current)) => {
// wait for a new epoch, then revoke the old one
return Err(anyhow::anyhow!("epoch {current} is current; create the next epoch before revoking"));
}
Err(e) => return Err(e),
} Prevention
- Always fetch chain_info().epoch and assert revoked_epoch < current before calling revoke_epochs.
- Use half-open ranges (0..current) in governance scripts to avoid off-by-one.
- Migrate to a new epoch first when retiring the current committee.
- Unit-test epoch arithmetic around reconfiguration in governance tooling.
When it happens
Trigger: Calling revoke_epochs(epoch) where epoch >= chain_info().epoch — typically passing the current epoch (e.g. Epoch(0) on a fresh network where current is also 0). Producers: governance scripts that compute 'revoke up to now' instead of 'up to previous'; off-by-one loops over 0..=current_epoch.
Common situations: Test suites revoking epochs after creating a committee without advancing to a new epoch; operators cleaning old committee data on a young network; version changes in the admin API where the epoch argument semantics shifted.
Related errors
- Block advances the chain's epoch from {start_epoch} to {end_
- InvalidCommitteeRemoval
- Incoming message bundle in block proposed to {chain_id} has
- Checkpoint precondition failed: Checkpoint must be the first
- InvalidCrossChainRequest
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/fdc2f8a04f0bbf0c.
Report an issue: GitHub.