{"record":{"id":"9086fb738f9fa198","repo":"jlcodes99/cockpit-tools","slug":"error-9086fb","errorCode":null,"errorMessage":"网关未在超时时间内返回唤醒结果，最后状态={}","messagePattern":"网关未在超时时间内返回唤醒结果，最后状态=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/modules/wakeup.rs","lineNumber":1634,"sourceCode":"        }\n\n        if let Some(err) = last_running_error {\n            crate::modules::logger::log_error(&format!(\n                \"[Wakeup] 网关轨迹持续错误且未恢复: cascade_id={}, last_status={}, error_code={:?}, message={}\",\n                cascade_id,\n                if last_status.is_empty() { \"-\" } else { &last_status },\n                err.error_code,\n                truncate_log_text(&err.message, 500)\n            ));\n            return Err(encode_wakeup_ui_error_payload(&err));\n        }\n\n        let message = if last_status.is_empty() {\n            \"网关未返回唤醒结果（轨迹中未出现 plannerResponse.modifiedResponse）\".to_string()\n        } else {\n            format!(\"网关未在超时时间内返回唤醒结果，最后状态={}\", last_status)\n        };\n        crate::modules::logger::log_error(&format!(\n            \"[Wakeup] 网关唤醒失败(超时/无结果): cascade_id={}, error={}\",\n            cascade_id, message\n        ));\n        Err(message)\n    }\n    .await;\n\n    if matches!(&wakeup_result, Err(err) if is_wakeup_cancelled_message(err)) {\n        let cleanup_client = client.clone();\n        let cleanup_url = format!(\"{}/DeleteCascadeTrajectory\", service_base);\n        let cleanup_cascade_id = cascade_id.clone();\n        tokio::spawn(async move {\n            let delete_resp = cleanup_client\n                .post(cleanup_url)\n                .header(reqwest::header::CONTENT_TYPE, \"application/json\")\n                .json(&json!({ \"cascadeId\": cleanup_cascade_id }))\n                .send()\n                .await;","sourceCodeStart":1616,"sourceCodeEnd":1652,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src-tauri/src/modules/wakeup.rs#L1616-L1652","documentation":"trigger_wakeup_via_client_gateway_once sends a wakeup request to the client gateway, then polls the cascade trajectory for a plannerResponse.modifiedResponse entry within a fixed timeout window. If the poll loop exhausts without seeing a result (and without any trajectory error), it returns Err with '网关未在超时时间内返回唤醒结果，最后状态={}'. The {} carries the last observed cascade status (empty means no trajectory was ever seen). It is a timeout/no-result guard, not a network failure per se: the gateway stayed reachable but never produced the planner's final modified response in time.","triggerScenarios":"trigger_wakeup_via_client_gateway -> trigger_wakeup_via_client_gateway_once starts a cascade, polls GetCascadeTrajectory every CLIENT_GATEWAY_POLL_INTERVAL_MS, and the loop completes all poll attempts without extract_wakeup_response_from_gateway_trajectory ever matching plannerResponse.modifiedResponse and without extract_gateway_error_from_trajectory returning an error. Also produced when the cascade stays stuck in a non-terminal last_status (e.g. RUNNING forever) or last_status is empty because the trajectory never materialized.","commonSituations":"Gateway/planner backend is slow or overloaded so the wakeup exceeds the poll budget; the model never emits a plannerResponse (agent hangs waiting on a tool or auth); proxy or gateway version change renames/moves the modifiedResponse field so extraction silently fails; cancel token fired late so polling ended before result; trajectory creation succeeded but the cascade never started (last_status empty).","solutions":["Check the gateway cascade status in the message tail: if still RUNNING, increase the poll timeout/interval budget or retry the wakeup once, since the run may simply need more time.","If last_status is empty, verify the cascade was actually created and the GetCascadeTrajectory endpoint/params (cascadeId) are correct before assuming a planner problem.","Inspect the raw gateway trajectory logs for plannerResponse shape; if the field moved or was renamed after a gateway upgrade, update extract_wakeup_response_from_gateway_trajectory's extraction keys.","Look upstream for why the planner hung (auth validation_url, tool hang, rate limits) — this error is downstream of the cascade never finishing.","If the trajectory kept erroring while RUNNING, rely on the last_running_error path instead; consider surfacing the trajectory error code to the user rather than a generic timeout."],"exampleFix":"// before: fixed budget poll loop\nwhile poll_idx < MAX_POLLS { poll().await?; poll_idx += 1; }\nErr(format!(\"网关未在超时时间内返回唤醒结果，最后状态={}\", last_status))\n// after: budget-aware retry + actionable status in message\nif is_cascade_status_running(&last_status) {\n    log_warn(\"wakeup timed out while RUNNING; retrying once\");\n    return trigger_wakeup_via_client_gateway_once(...).await; // retry\n}\nErr(format!(\"网关唤醒超时: cascade_id={}, last_status={}, 建议: 检查网关/认证后重试\", cascade_id, if last_status.is_empty() { \"UNKNOWN\" } else { &last_status }))","handlingStrategy":"retry","validationCode":"// Before calling, ensure gateway reachability and a sane budget\nlet health = reqwest::Client::new()\n    .get(format!(\"{}/health\", service_base))\n    .timeout(Duration::from_secs(5))\n    .send().await;\nif health.is_err() || !health.unwrap().status().is_success() {\n    return Err(\"gateway unreachable; fix connectivity before wakeup\".into());\n}","typeGuard":null,"tryCatchPattern":"match trigger_wakeup_via_client_gateway(...).await {\n    Err(msg) if msg.contains(\"超时时间内返回唤醒结果\") => {\n        // check last_status; retry once with a longer budget if cascade was RUNNING\n        log_warn(&format!(\"wakeup timeout, retrying: {}\", msg));\n        trigger_wakeup_via_client_gateway(...).await\n    }\n    other => other,\n}","preventionTips":["Set a poll budget that reflects realistic planner latency (measure P95 duration from successful wakeups) instead of a fixed guess.","Verify the cascade actually reaches a terminal status by watching last_status in logs; alert on cascades stuck RUNNING.","After gateway upgrades, smoke-test that plannerResponse.modifiedResponse still appears in trajectories and update the extractor keys.","Check upstream auth (validation_url) health before initiating wakeup, since auth hangs are a top cause of non-terminating cascades."],"tags":["timeout","network","gateway","polling","rust","tauri"],"backgroundTag":"upstream-request-timeout","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}