getzola/zola · error
Could not bind to address
Error message
Could not bind to address
What it means
Inside the spawned server thread, serve() awaits tokio::net::TcpListener::bind(&bind_address) and expects success. The expect fires when the configured address/port cannot be bound — most commonly the port is already in use by another process, or the user lacks permission for the port (privileged ports <1024) or the interface does not exist. Earlier in serve() a synchronous TcpListener::bind probe already ran; this is the actual async bind the server depends on, so failure means the dev server cannot listen.
Source
Thrown at src/cmd/serve.rs:651
thread::spawn(move || {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("Could not build tokio runtime");
rt.block_on(async {
let state = Arc::new(AppState { static_root, base_path, reload_tx });
let app = Router::new()
.route("/livereload.js", get(serve_livereload_js))
.route("/livereload", get(ws_handler))
.fallback(handle_request)
.layer(middleware::map_response(error_injection_middleware))
.with_state(state);
let listener = tokio::net::TcpListener::bind(&bind_address)
.await
.expect("Could not bind to address");
let local_addr = listener.local_addr().unwrap();
log::info!(
"Web server is available at {} (bound to {})\n",
constructed_base_url.replace(&bind_address.to_string(), &local_addr.to_string()),
local_addr
);
if open && let Err(err) = open::that(&constructed_base_url) {
log::error!("Failed to open URL in your browser: {err}");
}
axum::serve(listener, app).await.expect("Could not start web server");
});
});
// We watch for changes in the config by monitoring its parent directory, but we ignore all
// ordinary peer files. Map the parent directory back to the config file name to not confuseView on GitHub (pinned to 61d3082821)
Solutions
- Free the port: stop the other process listening on bind_address (lsof/netstat can identify it)
- Choose a different port via the --port flag or let the OS pick a free port
- Avoid privileged ports below 1024 or run with sufficient permissions
- Replace expect() with an anyhow error that includes bind_address and the underlying io::Error
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at src/cmd/serve.rs:651 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of getzola/zola@61d3082821 (2026-09-03).
Data as JSON: /api/errors/e206c55171f99df2.
Report an issue: GitHub.