nikivdev/code · error · anyhow::Error

codex app-server error: {}

Error message

codex app-server error: {}

What it means

The codex app-server answered the request, but the JSON-RPC response contained an "error" object instead of a result. codex_read_response extracts the error's "message" field (defaulting to "unknown codex app-server error") and bails with this message. This is a server-side rejection of the request, not a transport problem.

Source

Thrown at src/skills.rs:1136

            bail!("codex app-server response timed out");
        }
        let line = match lines.next() {
            Some(Ok(line)) => line,
            Some(Err(err)) => bail!("failed to read from codex app-server: {}", err),
            None => bail!("codex app-server closed stdout unexpectedly"),
        };
        if line.trim().is_empty() {
            continue;
        }
        let msg: serde_json::Value = serde_json::from_str(&line)
            .with_context(|| format!("invalid JSON from codex app-server: {}", line))?;
        if msg.get("id").and_then(|v| v.as_u64()) == Some(expected_id) {
            if let Some(err) = msg.get("error") {
                let message = err
                    .get("message")
                    .and_then(|v| v.as_str())
                    .unwrap_or("unknown codex app-server error");
                bail!("codex app-server error: {}", message);
            }
            return Ok(msg);
        }
    }
}

pub(crate) fn reload_codex_skills_for_cwd(cwd: &Path) -> Result<usize> {
    let codex_bin = configured_codex_bin_for_workdir(cwd);

    let mut child = Command::new(&codex_bin)
        .arg("app-server")
        .current_dir(cwd)
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()
        .context("failed to run codex app-server")?;

View on GitHub (pinned to a747e741ae)

Solutions

  1. Read the embedded server message after 'codex app-server error:' to identify the server-side cause
  2. Verify the request method/params match the codex app-server protocol version in use
  3. Ensure the app-server is fully initialized before sending requests
  4. Upgrade or align the codex binary with the client expectations

Example fix

// before: opaque without context of the request
bail!("codex app-server error: {}", message);
// after: include the request id for correlation
bail!("codex app-server error (id {}): {}", expected_id, message);
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate request params the server is known to reject
assert!(cwd.is_dir(), "cwd passed to app-server must exist: {}", cwd.display());

Try / catch

match codex_read_response(&mut lines, expected_id, deadline) {
    Ok(msg) => Ok(msg),
    Err(e) if e.to_string().starts_with("codex app-server error:") => {
        let server_msg = e.to_string().trim_start_matches("codex app-server error:");
        eprintln!("server rejected request: {server_msg}");
        // method/param mismatch => fix request, don't retry blindly
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: reload_codex_skills_for_cwd sends a request and the app-server replies with {"id": expected_id, "error": {"message": ...}} — e.g. the requested method is unknown, parameters are invalid, or the server is in a bad state.

Common situations: Protocol version mismatch so the method name is unsupported; invalid request payload (malformed cwd or params); app-server not initialized when the request arrives; permissions or workspace errors on the server side.

Related errors


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