getzola/zola · error

Could not start web server

Error message

Could not start web server

What it means

serve() reaches axum::serve(listener, app).await and expects the server loop to start (and, since .await is expected, to keep serving) without error. The expect fires if axum::serve returns an error while starting or accepting connections — e.g. the listener was closed underneath the server, an OS-level socket error occurred, or the runtime is being torn down. At this point binding already succeeded, so this panic indicates the accepted listener became unusable rather than a bad address.

Source

Thrown at src/cmd/serve.rs:664

                .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 confuse
    // the end user.
    let config_name =
        config_path.file_name().unwrap().to_str().expect("Config name is not valid UTF-8.");
    let watch_list = watchers
        .iter()
        .map(|w| if w == root_dir_str { config_name } else { w })
        .collect::<Vec<&str>>()
        .join(",");
    log::info!(
        "Listening for changes in {}{}{{{}}}",
        root_dir.display(),
        MAIN_SEPARATOR,
        watch_list

View on GitHub (pinned to 61d3082821)

Solutions

  1. Investigate why the bound listener became invalid (external close, fd exhaustion)
  2. Check OS socket limits (ulimit -n) if the error occurs under many connections
  3. Replace expect() with a logged error and graceful shutdown so a running site is not killed abruptly
  4. Ensure nothing else in the process closes or steals the listener fd
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at src/cmd/serve.rs:664 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/b418913d9d83fdc9. Report an issue: GitHub.