linera-io/linera-protocol · critical

Linera scan loop exited unexpectedly: {result:?}

Error message

Linera scan loop exited unexpectedly: {result:?}

What it means

In serve_loop's tokio::select!, the Linera scan loop task exited. This loop watches the bridge's own Linera chain for BurnEvents so withdrawals are relayed to the EVM side; if it dies (error return or panic), serve_loop fails fast because withdrawals would strand.

Source

Thrown at linera-bridge/src/relay/mod.rs:511

    // stream hiccup), and a missed `NewIncomingBundle` would otherwise strand
    // its messages until the next one. Reuse the monitor's scan interval as the
    // drain cadence; an empty inbox makes `process_inbox` a cheap no-op.
    let mut inbox_drain_interval = tokio::time::interval(monitor_scan_interval);
    // Consume the immediate first tick — the startup drain above already ran.
    inbox_drain_interval.tick().await;

    // ── Main loop: process chain operations + notifications ──
    tracing::info!("Listening for chain operations and notifications...");
    loop {
        tokio::select! {
            result = &mut chain_listener_handle => {
                anyhow::bail!("Chain listener exited unexpectedly: {result:?}");
            }
            result = &mut evm_scan_handle => {
                anyhow::bail!("EVM scan loop exited unexpectedly: {result:?}");
            }
            result = &mut linera_scan_handle => {
                anyhow::bail!("Linera scan loop exited unexpectedly: {result:?}");
            }
            result = &mut retry_handle => {
                anyhow::bail!("Retry loop exited unexpectedly: {result:?}");
            }
            result = &mut http_server_handle => {
                anyhow::bail!("HTTP server exited unexpectedly: {result:?}");
            }
            result = &mut admin_server_handle => {
                anyhow::bail!("Admin HTTP server exited unexpectedly: {result:?}");
            }
            _ = inbox_drain_interval.tick() => {
                // Periodic safety net for a missed `NewIncomingBundle`: sync and
                // drain the inbox so stranded messages (e.g. user burns) are
                // eventually processed even without a fresh notification.
                if let Err(e) = chain_client.synchronize_from_validators().await {
                    tracing::warn!("Periodic sync before inbox drain failed: {e}");
                } else {
                    match chain_client.process_inbox().await {

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Inspect relay logs for the Linera scan task's final error (it logs before exiting) — that is the root cause, this bail is only the propagation.
  2. Restore connectivity/authorization to the Linera validators, then restart the relay.
  3. If it was a panic decoding block events, fix the decoder for the new event shape and redeploy.
  4. Run the relay under a supervisor (systemd Restart=always, docker restart policy) since serve_loop intentionally exits on any task death.

Example fix

// before
result = &mut linera_scan_handle => {
    anyhow::bail!("Linera scan loop exited unexpectedly: {result:?}");
}

// after: include the outcome kind in the fatal error
result = &mut linera_scan_handle => {
    let kind = match &result { Ok(()) => "returned", Err(j) if j.is_panic() => "panicked", Err(_) => "aborted" };
    anyhow::bail!("Linera scan loop {kind}: {result:?}; see prior scan-loop logs for root cause");
}
Defensive patterns

Strategy: retry

Validate before calling

// Before serving: one successful sync proves Linera connectivity/authorization
chain_client.synchronize_from_validators().await?;

Try / catch

// Fatal by design; restart the relay process. Log the scan task's last error for diagnosis.

Prevention

When it happens

Trigger: The Linera scan future returns Err after exhausting its retries (chain client cannot synchronize with validators, chain query failures) or panics while parsing block events; the task is also prodded by scan_notify on every new block notification, so notification-driven code paths run inside it.

Common situations: Validators unreachable for an extended period; the bridge chain's client key not authorized (multisig leader changed); a malformed/unexpected event in a block after an application upgrade panics the decoder.

Related errors


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