linera-io/linera-protocol · error · anyhow
Failed to start node service
Error message
Failed to start node service
What it means
`run_node_service_with_all_options` spawns `linera service --port <port>` (default 8080, plus any CLIENT_SERVICE_ENV args) and then polls `GET http://localhost:{port}/` up to 10 times with sleeps of 0..9 seconds (~45s budget). Any successful HTTP response counts as started, so the bail means the child never answered at all: it died, cannot bind the port, or started too slowly. Used by e2e tests like `test_wasm_end_to_end_counter_subscription`.
Source
Thrown at linera-service/src/cli_wrappers/wallet.rs:572
}
for (name, secs) in subscription_ttls {
command.args(["--subscription-ttl-secs", &format!("{name}={secs}")]);
}
let child = command
.args(["--port".to_string(), port.to_string()])
.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!("Node service has started");
return Ok(NodeService::new(port, child));
} else {
tracing::warn!("Waiting for node service to start");
}
}
bail!("Failed to start node service");
}
/// Runs `linera service` with a controller application.
pub async fn run_node_service_with_controller(
&self,
port: impl Into<Option<u16>>,
process_inbox: ProcessInbox,
controller_id: &ApplicationId,
operators: &[(String, PathBuf)],
) -> Result<NodeService> {
let port = port.into().unwrap_or(8080);
let mut command = self.command().await?;
command.arg("service");
if let ProcessInbox::Skip = process_inbox {
command.arg("--listener-skip-process-inbox");
}
if let Ok(var) = env::var(CLIENT_SERVICE_ENV) {
command.args(var.split_whitespace());View on GitHub (pinned to 6c226ddcb3)
Solutions
- Check whether the port is free (`lsof -i :8080`); free it or pass a different port to the wrapper
- Run `linera service --port <port>` manually with the same wallet/config to see the child's startup error
- Watch for the 'Waiting for node service to start' warns and inspect the child process output/stderr
- After cleanup, retry the wrapper call; on slow runners choose an explicit free port instead of the 8080 default
Example fix
// before let service = client.run_node_service_with_all_options(None, ...).await?; // port defaults to 8080 // after let service = client.run_node_service_with_all_options(Some(18080), ...).await?; // explicit free port
Defensive patterns
Strategy: retry
Validate before calling
// Pick a free port up front instead of relying on the 8080 default.
let port = linera_base::port::get_free_endpoint().await?
.port()
.expect("endpoint has a port");
let service = client.run_node_service_with_all_options(Some(port), ...).await?; Try / catch
match client.run_node_service_with_all_options(Some(port), ...).await {
Err(e) if e.to_string() == "Failed to start node service" => {
// poll already ran ~45s; failure is structural (dead child / port conflict)
free_port_or_pick_another(port).await?;
client.run_node_service_with_all_options(Some(new_port), ...).await?
}
result => result,
} Prevention
- Pass an explicit free port to every spawned service (node service, faucet) — never stack on 8080 defaults
- Drop NodeService handles deterministically in tests so children die and ports are released
- When it fails, run `linera service` manually with the same wallet and env (CLIENT_SERVICE_ENV is injected!) to see the child's error
When it happens
Trigger: The `linera service` child fails to bind its port (already in use), crashes on startup (bad wallet/config, storage error, invalid extra args from CLIENT_SERVICE_ENV), or takes longer than the ~45s polling budget on a loaded machine.
Common situations: Default port 8080 occupied by another dev service or proxy; a previous NodeService leaked and still holds the port; an invalid wallet/keystore making the child exit immediately; CI runners under heavy load exceeding the fixed retry budget.
Related errors
- Failed to start faucet
- Failed to start {nickname}
- Query "{}" failed after {} retries.
- Expected a tip hash string, but got {invalid_data:?} instead
- failed to create SQLite database file: {database_url}, error
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/23fba053feb019f7.
Report an issue: GitHub.