openai/codex · error · anyhow::Error

failed to read start time for pid-managed app server {pid}

Error message

failed to read start time for pid-managed app server {pid}

What it means

After spawning the managed app-server (and whenever validating a recorded pid), the backend fingerprints the process by running 'ps -p <pid> -o lstart='; a non-zero exit from ps produces this bail. Most often the freshly spawned child already exited (broken codex binary, immediate crash, unwritable CODEX_HOME, occupied control socket), so ps reports no such process; a ps that lacks lstart support (busybox) also exits non-zero. In the start path (pid.rs:200) the daemon then kills the child, removes the pid file, and appends the child's stderr log tail to the error context.

Source

Thrown at codex-rs/app-server-daemon/src/backend/pid.rs:708

}

#[cfg(not(unix))]
async fn inspect_empty_pid_reservation(
    _pid_path: &Path,
    _lock_path: &Path,
) -> Result<EmptyPidReservation> {
    Ok(EmptyPidReservation::Stale)
}

#[cfg(unix)]
async fn read_process_start_time(pid: u32) -> Result<String> {
    let output = Command::new("ps")
        .args(["-p", &pid.to_string(), "-o", "lstart="])
        .output()
        .await
        .context("failed to invoke ps for pid-managed app server")?;
    if !output.status.success() {
        bail!("failed to read start time for pid-managed app server {pid}");
    }

    let start_time = String::from_utf8(output.stdout)
        .context("pid-managed app server start time was not utf-8")?;
    let start_time = start_time.trim();
    if start_time.is_empty() {
        bail!("pid-managed app server {pid} has no recorded start time");
    }
    Ok(start_time.to_string())
}

#[cfg(all(test, unix))]
#[path = "pid_tests.rs"]
mod tests;

View on GitHub (pinned to 339751715c)

Solutions

  1. Print the error with the full anyhow chain ({err:#}) — the daemon appends the managed server's stderr tail (<pid file>.stderr.log, last 4KB), which usually names the real crash.
  2. Reproduce the spawn manually with the exact argv from command_args (pid.rs:413): '<codex_bin> app-server --listen unix://' — and fix whatever makes it exit.
  3. Ensure a full procps ps is installed: 'ps -p 1 -o lstart=' must print a date (busybox ps lacks lstart=).
  4. Remove a stale or foreign control socket, or stop the conflicting instance, then retry start.
  5. Retry the lifecycle start after cleanup — the failed child and its pid file are already removed by the error path.

Example fix

// before: error chain left unread, crash reason hidden
run(LifecycleCommand::Start).await?;

// after: surface the context chain (includes 'Managed app-server stderr (...)' tail), then verify the environment
if let Err(err) = run(LifecycleCommand::Start).await {
    eprintln!("{err:#}");
}
// daemon depends on this host's ps:
// ps -p $$ -o lstart=   (must print a start date, not an error)
Defensive patterns

Strategy: retry

Validate before calling

// preflight before LifecycleCommand::Start
let ps = std::process::Command::new("ps")
    .args(["-p", "1", "-o", "lstart="])
    .output()?;
if !ps.status.success() || ps.stdout.trim().is_empty() {
    anyhow::bail!("this host's ps cannot report lstart; daemon start will fail");
}
// and confirm the managed binary starts:
// <CODEX_HOME> managed codex: `codex app-server --help`

Try / catch

if let Err(err) = run(LifecycleCommand::Start).await {
    eprintln!("{err:#}"); // context chain includes the 'Managed app-server stderr (...)' tail naming the real crash
    // fix the cause, then retry exactly once
    run(LifecycleCommand::Start).await?;
}

Prevention

When it happens

Trigger: start() at pid.rs:200 invokes ps immediately after spawn — if the child exits first, ps exits 1 and this fires; the error path cleans up and attaches the stderr tail. Also raised from process_matches_record (pid.rs:582) when revalidating a recorded pid, tolerated there only when the process no longer exists. On slim images, busybox ps rejects '-o lstart=' with a non-zero exit for every pid.

Common situations: Corrupt or mismatched managed codex binary under CODEX_HOME after a partial update; app-server crashing at boot from bad config or a conflicting listener; Docker/CI images without full procps installed; spawn/ps races on very slow or loaded machines.

Related errors


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