nikivdev/code · error

kill failed

Error message

kill failed

What it means

This error is thrown by terminate_process when a `kill` command was executed against a PID but the command exited with a non-zero status. It means the OS refused or failed to terminate the target process (the earlier `.context("failed to kill process")` only covers spawn/IO errors). Callers (ensure_server, stop_server) surface it when trying to stop a previously running server instance.

Source

Thrown at src/log_server.rs:298

fn process_alive(pid: u32) -> bool {
    Command::new("kill")
        .arg("-0")
        .arg(pid.to_string())
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

fn terminate_process(pid: u32) -> Result<()> {
    let status = Command::new("kill")
        .arg(pid.to_string())
        .status()
        .context("failed to kill process")?;
    if status.success() {
        Ok(())
    } else {
        bail!("kill failed")
    }
}

async fn health() -> impl IntoResponse {
    Json(json!({ "status": "ok" }))
}

#[derive(Debug, Deserialize)]
struct CodexSkillsQuery {
    path: Option<String>,
    limit: Option<usize>,
}

#[derive(Debug, Deserialize)]
struct CodexEvalQuery {
    path: Option<String>,
    limit: Option<usize>,
}

View on GitHub (pinned to a747e741ae)

Solutions

  1. Check the process with `ps -p <pid>` — if it does not exist, delete the stale PID file and retry.
  2. Run the stop/ensure command as the same user (or with sudo) that owns the target process.
  3. Manually kill the process (`kill -9 <pid>`) if it ignores SIGTERM, then clean up the PID file.
  4. Update the PID file to point at the correct current server PID before calling stop_server again.

Example fix

// before
ensure_server(&pid_path)?; // fails with "kill failed" on stale pid
// after
if let Ok(pid) = std::fs::read_to_string(&pid_path) {
    if !process_exists(pid.trim()) {
        let _ = std::fs::remove_file(&pid_path); // clear stale pid first
    }
}
ensure_server(&pid_path)?;
Defensive patterns

Strategy: try-catch

Validate before calling

let pid = std::fs::read_to_string("server.pid")?;
let alive = std::process::Command::new("ps")
    .args(["-p", pid.trim()])
    .status()
    .map(|s| s.success())
    .unwrap_or(false);
if !alive { let _ = std::fs::remove_file("server.pid"); }

Type guard

fn process_alive(pid: u32) -> bool {
    std::process::Command::new("kill").args(["-0", &pid.to_string()]).status().map(|s| s.success()).unwrap_or(false)
}

Try / catch

match stop_server(&pid_path) {
    Ok(()) => {},
    Err(e) if e.to_string() == "kill failed" => {
        // stale pid or permission issue: clear pid file, check ownership, retry once
        let _ = std::fs::remove_file(&pid_path);
        stop_server(&pid_path)?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling stop_server or ensure_server when the recorded PID no longer exists (stale PID file), the process is owned by another user (permission denied), or the PID was reused by an unrelated process.

Common situations: A server crashed and left a stale PID file; running under a different user than the one that started the server; PID recycled by the OS after reboot.


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/e05109b8449870d9. Report an issue: GitHub.