BigPizzaV3/CodexPlusPlus · error · anyhow::Error

等待 Codex 回复超时

Error message

等待 Codex 回复超时

What it means

run_turn drives one Codex turn over the app-server JSON-RPC stdio protocol and waits until both the turn/start response arrives and a turn/completed (or idle thread/status/changed) notification is seen, bounded by TURN_TIMEOUT. This error means the deadline expired first: Codex never answered or never finished the turn within the budget.

Source

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

        }
        self.write_json(&json!({
            "jsonrpc": "2.0",
            "id": id,
            "method": "turn/start",
            "params": params
        }))
        .await?;

        let mut response_received = false;
        let mut turn_completed = false;
        let mut reply_parts = Vec::new();
        let mut model = self.config.model.trim().to_string();
        let mut usage = TurnUsage::default();
        let deadline = tokio::time::Instant::now() + TURN_TIMEOUT;
        while !response_received || !turn_completed {
            let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
            if remaining.is_zero() {
                bail!("等待 Codex 回复超时");
            }
            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) {
                if let Some(error) = rpc_error(&message) {
                    bail!("Codex turn/start 失败:{error}");
                }
                let result = message.get("result").cloned().unwrap_or(Value::Null);
                if extract_turn_id(&result).is_none() {
                    bail!("Codex turn/start 未返回 turn id");
                }
                if model.is_empty() {
                    model = extract_model(&result).unwrap_or_default();
                }
                if let Some(reported_usage) = extract_turn_usage(&result) {

View on GitHub (pinned to f2074595a2)

Solutions

  1. Retry the turn with a smaller prompt or less requested output so it finishes inside the budget
  2. Run one manual codex turn to confirm login and health before starting the connector
  3. Raise TURN_TIMEOUT in the crate if the workload legitimately runs long
  4. Keep codex-plus-core and the codex app-server on matched versions
Defensive patterns

Strategy: retry

Try / catch

let reply = match server.run_turn(&thread_id, prompt).await {
    Ok(r) => r,
    Err(e) if e.to_string().contains("等待 Codex 回复超时") => {
        server.close().await;
        let mut server = CodexAppServer::start(config).await?;
        server.run_turn(&thread_id, trimmed(prompt)).await?
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: A long generation exceeding TURN_TIMEOUT; the codex app-server hung on network or auth; the completion notification was opted out or used a method the loop does not match, so turn_completed never became true.

Common situations: Slow model or oversized prompt; codex CLI waiting for login or authorization; version skew where the app-server emits different completion events than this crate matches.

Related errors


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