openai/codex · error · anyhow::Error

server stopped unexpectedly

Error message

server stopped unexpectedly

What it means

run_main's happy path never returns normally - it awaits the HTTP server. If the server future completes without an intentional shutdown, control falls through to Err(anyhow!("server stopped unexpectedly")) as a sentinel: the accept/serve loop ended on its own, and the actual cause is normally logged just above it (for example 'forwarding error: ...' lines).

Source

Thrown at codex-rs/responses-api-proxy/src/lib.rs:135

        std::thread::spawn(move || {
            if http_shutdown && request.method() == &Method::Get && request.url() == "/shutdown" {
                let _ = request.respond(Response::new_empty(StatusCode(200)));
                std::process::exit(0);
            }

            if let Err(e) = forward_request(
                &client,
                auth_header,
                &forward_config,
                dump_dir.as_deref(),
                request,
            ) {
                eprintln!("forwarding error: {e}");
            }
        });
    }

    Err(anyhow!("server stopped unexpectedly"))
}

fn bind_listener(port: Option<u16>) -> Result<(TcpListener, SocketAddr)> {
    let addr = SocketAddr::from(([127, 0, 0, 1], port.unwrap_or(0)));
    let listener = TcpListener::bind(addr).with_context(|| format!("failed to bind {addr}"))?;
    let bound = listener.local_addr().context("failed to read local_addr")?;
    Ok((listener, bound))
}

fn write_server_info(path: &Path, port: u16) -> Result<()> {
    if let Some(parent) = path.parent()
        && !parent.as_os_str().is_empty()
    {
        fs::create_dir_all(parent)?;
    }

    let info = ServerInfo {
        port,

View on GitHub (pinned to 339751715c)

Solutions

  1. Read stderr above this error - the root cause (accept or forwarding error) is printed there
  2. Check whether something killed the process or its socket (OOM killer, orchestrator stop, timeout wrapper)
  3. Restart the proxy under a supervisor with backoff
  4. If it recurs with clean logs, capture stderr and file an upstream issue - intentional shutdown returns Ok, not this error
Defensive patterns

Strategy: retry

Try / catch

match run_main(args).await {
    Err(e) if e.to_string() == "server stopped unexpectedly" => {
        // fatal but restartable: re-launch with backoff under a supervisor
        supervisor_restart_with_backoff();
    }
    other => other,
}

Prevention

When it happens

Trigger: The bound listener closes or the serve loop exits at runtime: a fatal accept error, the listener closed externally, or the server task terminating while run_main is still waiting on shutdown signals.

Common situations: Container orchestrators or supervisors closing sockets; running the proxy under a timeout wrapper that tears down the listener; internal errors aborting the serve loop; tests dropping the server handle.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/e343b431c4489c71. Report an issue: GitHub.