BigPizzaV3/CodexPlusPlus · error · anyhow::Error

Codex app-server {method} 失败:{error}

Error message

Codex app-server {method} 失败:{error}

What it means

The JSON-RPC response to initialize, thread/start or thread/resume carried an error object; request() rethrows its message with the method name prefixed. Typical causes are an invalid or expired threadId on thread/resume, or an initialize payload the installed app-server rejects.

Source

Thrown at crates/codex-plus-core/src/connect/app_server.rs:286

            "params": params
        }))
        .await?;
        let deadline = tokio::time::Instant::now() + timeout;
        loop {
            let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
            if remaining.is_zero() {
                bail!("Codex app-server {method} 请求超时");
            }
            let message = self.read_message(remaining).await?;
            if is_server_request(&message) {
                self.reject_server_request(&message).await?;
                continue;
            }
            if response_id(&message) != Some(id) {
                continue;
            }
            if let Some(error) = rpc_error(&message) {
                bail!("Codex app-server {method} 失败:{error}");
            }
            return Ok(message.get("result").cloned().unwrap_or(Value::Null));
        }
    }

    async fn read_message(&mut self, timeout: Duration) -> anyhow::Result<Value> {
        loop {
            let line = tokio::time::timeout(timeout, self.stdout.next_line())
                .await
                .context("等待 Codex app-server 响应超时")??;
            let Some(line) = line else {
                self.running = false;
                let exit = self.child.try_wait().ok().flatten();
                bail!(
                    "Codex app-server 已关闭{}",
                    exit.map(|status| format!(":{status}")).unwrap_or_default()
                );
            };

View on GitHub (pinned to f2074595a2)

Solutions

  1. Drop the stored thread id and retry with thread/start, the connector already implements this fallback for resume failures
  2. Read the appended error text to find the offending field
  3. Align codex-plus-core with the installed codex app-server version
  4. Clear stale connect-session state for the account if resume keeps failing

Example fix

// before
let thread_id = server.prepare_thread(saved.as_deref()).await?;
// after: resume failure falls back to a new thread, as the connector does
let thread_id = match server.prepare_thread(saved.as_deref()).await {
    Ok(id) => id,
    Err(_) => server.prepare_thread(None).await?,
};
Defensive patterns

Strategy: fallback

Try / catch

let thread_id = match server.prepare_thread(saved.as_deref()).await {
    Ok(id) => id,
    Err(_) => server.prepare_thread(None).await?,
};

Prevention

When it happens

Trigger: prepare_thread(Some(id)) where the saved thread was deleted or belongs to another codex version; initialize capabilities object rejected after an app-server protocol change.

Common situations: Session files persisted across a codex upgrade; thread rolled by retention; version skew between codex-plus-core and the codex CLI.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@f2074595a2 (2026-08-23). Data as JSON: /api/errors/5d027148db36192d. Report an issue: GitHub.