{"record":{"id":"d25adb3ab7901dea","repo":"BigPizzaV3/CodexPlusPlus","slug":"codex","errorCode":null,"errorMessage":"等待 Codex 回复超时","messagePattern":"等待 Codex 回复超时","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/connect/app_server.rs","lineNumber":145,"sourceCode":"        }\n        self.write_json(&json!({\n            \"jsonrpc\": \"2.0\",\n            \"id\": id,\n            \"method\": \"turn/start\",\n            \"params\": params\n        }))\n        .await?;\n\n        let mut response_received = false;\n        let mut turn_completed = false;\n        let mut reply_parts = Vec::new();\n        let mut model = self.config.model.trim().to_string();\n        let mut usage = TurnUsage::default();\n        let deadline = tokio::time::Instant::now() + TURN_TIMEOUT;\n        while !response_received || !turn_completed {\n            let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());\n            if remaining.is_zero() {\n                bail!(\"等待 Codex 回复超时\");\n            }\n            let message = self.read_message(remaining).await?;\n            if is_server_request(&message) {\n                self.reject_server_request(&message).await?;\n                continue;\n            }\n            if response_id(&message) == Some(id) {\n                if let Some(error) = rpc_error(&message) {\n                    bail!(\"Codex turn/start 失败：{error}\");\n                }\n                let result = message.get(\"result\").cloned().unwrap_or(Value::Null);\n                if extract_turn_id(&result).is_none() {\n                    bail!(\"Codex turn/start 未返回 turn id\");\n                }\n                if model.is_empty() {\n                    model = extract_model(&result).unwrap_or_default();\n                }\n                if let Some(reported_usage) = extract_turn_usage(&result) {","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/f2074595a281bc057525c748175c8eb9805b0673/crates/codex-plus-core/src/connect/app_server.rs#L127-L163","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the turn with a smaller prompt or less requested output so it finishes inside the budget","Run one manual codex turn to confirm login and health before starting the connector","Raise TURN_TIMEOUT in the crate if the workload legitimately runs long","Keep codex-plus-core and the codex app-server on matched versions"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let reply = match server.run_turn(&thread_id, prompt).await {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"等待 Codex 回复超时\") => {\n        server.close().await;\n        let mut server = CodexAppServer::start(config).await?;\n        server.run_turn(&thread_id, trimmed(prompt)).await?\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Keep prompts bounded so turns finish well inside TURN_TIMEOUT","Verify codex login before starting long-running connectors","Pin matched codex and codex-plus-core versions"],"tags":["timeout","codex","app-server","turn"],"backgroundTag":"llm-request-timeout","analyzedSha":"f2074595a281bc057525c748175c8eb9805b0673","analyzedAt":"2026-08-23T12:52:24.489Z","contentChangedAt":"2026-08-23T12:52:24.489Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}