linera-io/linera-protocol · error · anyhow

Failed to start faucet

Error message

Failed to start faucet

What it means

`run_faucet` spawns `linera faucet --port <p> --amount <a> --storage-path <tmp>/faucet_storage.sqlite [chain_id]` and polls `GET http://localhost:{port}/` up to 10 times with 0..9s sleeps. Any successful HTTP response counts as started; the bail means the faucet never answered — it crashed at startup or the port was unavailable. Heavy users include the e2e faucet/reconfiguration tests.

Source

Thrown at linera-service/src/cli_wrappers/wallet.rs:717

                "--storage-path".to_string(),
                storage_path.to_string_lossy().to_string(),
            ]);
        if let Some(chain_id) = chain_id {
            command.arg(chain_id.to_string());
        }
        let child = command.spawn_into()?;
        let client = reqwest_client();
        for i in 0..10 {
            linera_base::time::timer::sleep(Duration::from_secs(i)).await;
            let request = client.get(format!("http://localhost:{port}/")).send().await;
            if request.is_ok() {
                tracing::info!("Faucet has started");
                return Ok(FaucetService::new(port, child, temp_dir));
            } else {
                tracing::debug!("Waiting for faucet to start");
            }
        }
        bail!("Failed to start faucet");
    }

    /// Runs `linera local-balance`.
    pub async fn local_balance(&self, account: Account) -> Result<Amount> {
        let stdout = self
            .command()
            .await?
            .arg("local-balance")
            .arg(account.to_string())
            .spawn_and_wait_for_stdout()
            .await?;
        let amount = stdout
            .trim()
            .parse()
            .context("error while parsing the result of `linera local-balance`")?;
        Ok(amount)
    }

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Give the faucet its own port (do not reuse the node-service port, especially the 8080 default)
  2. Check for and kill stale listeners: `lsof -i :<port>`
  3. Run `linera faucet --port <p> --amount <a>` manually with the same args to see its startup error
  4. Ensure the faucet's chain exists and is funded before starting it, then retry

Example fix

// before
let service = client.run_node_service_with_options(Some(8080), ...).await?;
let faucet = client.run_faucet(None /* 8080 again! */, ...).await?; // port collision

// after
let service = client.run_node_service_with_options(Some(18080), ...).await?;
let faucet = client.run_faucet(Some(18081), ...).await?;
Defensive patterns

Strategy: retry

Validate before calling

// Never share the default 8080 between faucet and node service.
let faucet_port = linera_base::port::get_free_endpoint().await?.port().unwrap();
let faucet = client.run_faucet(Some(faucet_port), Some(chain_id), amount).await?;

Try / catch

match client.run_faucet(Some(port), Some(chain_id), amount).await {
    Err(e) if e.to_string() == "Failed to start faucet" => {
        // child died or port busy; check lsof, verify the chain is funded/synced, retry
        ensure_port_free(port)?;
        client.run_faucet(Some(port), Some(chain_id), amount).await
    }
    result => result,
}

Prevention

When it happens

Trigger: The faucet child fails to bind its port (default 8080, commonly colliding with a node service), exits because the given chain/amount config is invalid, or comes up slower than the ~45s polling budget.

Common situations: Starting faucet and node service both on the default 8080 in the same test; the faucet's chain not yet synced/registered; leftover faucet process holding the port; slow CI machines.

Related errors


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