linera-io/linera-protocol · error · Error

MetaMask is not available

Error message

MetaMask is not available

What it means

The ChainClient guards concurrent proposals with a PendingProposal. If you try to build/propose a new block while a previous proposal is still pending (sent but not yet confirmed by a quorum), prepare... returns Error::BlockProposalError with this message. The pending block must be resolved first — either confirmed via certificates from validators, or explicitly retried — because two in-flight proposals for the same height cannot both succeed.

Source

Thrown at web/@linera/metamask/src/signer.ts:34

 * and interacts with it using EIP-191-compliant requests. It provides a secure
 * mechanism for message signing through the user's MetaMask wallet.
 * 
 * ⚠️ WARNING: This signer requires MetaMask to be installed and unlocked in the browser.
 * It will throw errors if MetaMask is unavailable, the user rejects a request, or
 * if the requested signer is not among the connected accounts.
 * 
 * The `MetaMask` signer verifies that the connected account matches the specified
 * owner address before signing a message. All messages are encoded as hexadecimal
 * strings and signed using the `personal_sign` method.
 * 
 * Suitable for production use where MetaMask is the expected signer interface.
 */
export default class Signer implements SignerInterface {
  private provider: ethers.BrowserProvider;

  constructor() {
    if (typeof window === "undefined" || !window.ethereum) {
      throw new Error("MetaMask is not available");
    }
    this.provider = new ethers.BrowserProvider(window.ethereum!);
  }

  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");
    }

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Run `linera retry-pending-block [CHAIN_ID]` (or client retry_pending_block / the node-service retry_pending_block endpoint) to commit or discard the outstanding proposal first.
  2. If the pending block is obsolete, explicitly drop it and then propose the new block in a fresh call.
  3. Serialize proposals per chain in your application (one in-flight proposal at a time) so the guard never trips.
  4. After retrying, verify the block got confirmed by checking next_block_height advanced before issuing new operations.

Example fix

# before: issuing a new operation while a proposal is pending
linera transfer --amount 5 ... # BlockProposalError: already has a pending block

# after: settle the pending block first
linera retry-pending-block <CHAIN_ID>
linera transfer --amount 5 ...
Defensive patterns

Strategy: retry

Validate before calling

// Application-level guard: serialize proposals per chain
if proposal_in_flight.contains(&chain_id) {
    return Err(anyhow::anyhow!("a proposal is already pending for {chain_id}; finish it first"));
}

Try / catch

match client.prepare_block(operations).await {
    Ok(block) => block,
    Err(Error::BlockProposalError(msg)) if msg.contains("pending block") => {
        client.retry_pending_block().await?; // or node-service retry_pending_block
        client.prepare_block(operations).await?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the block-preparation entry point (which takes proposal_guard: &mut Option<PendingProposal>) twice without the first proposal being finalized: e.g. propose a block, the client crashes or the network stalls before confirmation, then call the same flow again. The guard ensure!(proposal_guard.is_none()) fires.

Common situations: Process restart after a failed submit; validator timeouts leaving the block unconfirmed; automation loops that re-issue 'transfer' commands while a previous one is in flight; the JSON-RPC service receiving two concurrent requests for the same chain.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/dc301d0c189ae243. Report an issue: GitHub.