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
- Drop the stored thread id and retry with thread/start, the connector already implements this fallback for resume failures
- Read the appended error text to find the offending field
- Align codex-plus-core with the installed codex app-server version
- 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
- Always pair thread/resume with a thread/start fallback
- Clear persisted thread ids after codex upgrades
- Log the method-prefixed error text to identify the rejected field
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
- Codex turn/start 失败:{error}
- Codex app-server {method} 请求超时
- No injectable Codex page target found
- 等待 Codex 回复超时
- Codex turn/start 未返回 turn id
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@f2074595a2 (2026-08-23).
Data as JSON: /api/errors/5d027148db36192d.
Report an issue: GitHub.