{"record":{"id":"207a33fcc00927a1","repo":"openai/codex","slug":"pid-managed-app-server-pid-has-no-recorded-start","errorCode":null,"errorMessage":"pid-managed app server {pid} has no recorded start time","messagePattern":"pid-managed app server (.+?) has no recorded start time","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/app-server-daemon/src/backend/pid.rs","lineNumber":715,"sourceCode":"    Ok(EmptyPidReservation::Stale)\n}\n\n#[cfg(unix)]\nasync fn read_process_start_time(pid: u32) -> Result<String> {\n    let output = Command::new(\"ps\")\n        .args([\"-p\", &pid.to_string(), \"-o\", \"lstart=\"])\n        .output()\n        .await\n        .context(\"failed to invoke ps for pid-managed app server\")?;\n    if !output.status.success() {\n        bail!(\"failed to read start time for pid-managed app server {pid}\");\n    }\n\n    let start_time = String::from_utf8(output.stdout)\n        .context(\"pid-managed app server start time was not utf-8\")?;\n    let start_time = start_time.trim();\n    if start_time.is_empty() {\n        bail!(\"pid-managed app server {pid} has no recorded start time\");\n    }\n    Ok(start_time.to_string())\n}\n\n#[cfg(all(test, unix))]\n#[path = \"pid_tests.rs\"]\nmod tests;\n","sourceCodeStart":697,"sourceCodeEnd":723,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/app-server-daemon/src/backend/pid.rs#L697-L723","documentation":"read_process_start_time treats a ps exit code of 0 with empty stdout as a broken fingerprint: the daemon records the process's lstart string as the identity of the managed server (PidRecord.process_start_time), and an empty one cannot be compared later during stale-record detection. Standard procps always prints a start time for a live pid, so an empty result points at a non-standard ps, a procfs that hides start times, or an exotic patched procps build.","triggerScenarios":"Same call sites as [44]: start() recording the spawned child (pid.rs:200) or process_matches_record revalidating a pid (pid.rs:582), where 'ps -p <pid> -o lstart=' exits 0 but prints only whitespace.","commonSituations":"Hardened hosts with hidepid or restricted /proc mounts; minimal or custom ps builds in containers; enterprise/NAS distros shipping a patched procps that accepts the flag but emits nothing.","solutions":["Run 'ps -p <pid> -o lstart=' by hand for a live pid — if it prints nothing, fix or replace the ps implementation (install full procps).","Check /proc mount options (hidepid) and container seccomp/apparmor profiles that starve ps of process data.","Move the daemon to a host with a standard procps if the environment cannot report start times.","Read the appended stderr log tail to rule out an app-server crash masquerading as a fingerprint failure."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// must print a start date before relying on the daemon\nlet out = std::process::Command::new(\"ps\")\n    .args([\"-p\", \"1\", \"-o\", \"lstart=\"])\n    .output()?;\nif out.stdout.trim().is_empty() {\n    anyhow::bail!(\"ps reports no start time on this host; pid records would be unusable\");\n}","typeGuard":null,"tryCatchPattern":"Treat like [44]: on Err print the anyhow chain (stderr tail included), verify ps behavior manually, then retry start once the environment reports lstart.","preventionTips":["Standardize on full procps in daemon host images.","Avoid hidepid/restricted procfs mounts on hosts that run the daemon.","Smoke-test 'ps -p $$ -o lstart=' when provisioning a new daemon host."],"tags":["rust","codex","daemon","unix","ps","procfs"],"backgroundTag":"empty-command-output","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}