{"record":{"id":"e9c71f174014e12f","repo":"Hmbown/CodeWhale","slug":"cloud-agent-sandbox-listing-failed-http-status","errorCode":null,"errorMessage":"Cloud agent sandbox listing failed (HTTP {status}).","messagePattern":"Cloud agent sandbox listing failed \\(HTTP (.+?)\\)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/cloud_dispatch.rs","lineNumber":1804,"sourceCode":"        // The provider's list call takes a JSON-encoded exact-match labels\n        // filter (same OpenAPI family as create/get/delete above); filtering\n        // on the product tag keeps the response to Codewhale dispatch\n        // sandboxes only — never the user's own sandboxes on a shared key.\n        let mut url = Self::control_plane_url(\"sandbox\")?;\n        url.query_pairs_mut().append_pair(\n            \"labels\",\n            &format!(\"{{\\\"{SANDBOX_PRODUCT_LABEL}\\\":\\\"{SANDBOX_PRODUCT_VALUE}\\\"}}\"),\n        );\n        let response = Self::send_json(\n            reqwest::Method::GET,\n            &url,\n            &api_key,\n            serde_json::Value::Null,\n        )?;\n        let status = response.status();\n        let text = response.text().unwrap_or_default();\n        if !status.is_success() {\n            bail!(\"Cloud agent sandbox listing failed (HTTP {status}).\");\n        }\n        let parsed: serde_json::Value = serde_json::from_str(&text)\n            .context(\"the cloud agent service returned an unreadable sandbox list\")?;\n        let rows = parsed.as_array().cloned().unwrap_or_default();\n        let mut sandboxes = Vec::new();\n        for row in rows {\n            let sandbox_id = row\n                .get(\"id\")\n                .and_then(serde_json::Value::as_str)\n                .unwrap_or(\"\")\n                .trim()\n                .to_string();\n            if !valid_sandbox_id(&sandbox_id) {\n                continue;\n            }\n            let job_id = row\n                .get(\"labels\")\n                .and_then(|labels| labels.get(SANDBOX_JOB_LABEL))","sourceCodeStart":1786,"sourceCodeEnd":1822,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/cloud_dispatch.rs#L1786-L1822","documentation":"Thrown by `list_job_sandboxes` when the control-plane sandbox listing request returns a non-2xx HTTP status. The dispatcher uses this listing (with JSON-encoded exact-match labels) to find/reconcile job sandboxes; a failed list means orphan detection and reconciliation cannot run. The provider status is embedded in the message for diagnosis.","triggerScenarios":"Any code path that enumerates labeled sandboxes when the provider list endpoint returns non-success: auth failure (401), rate limit (429), control-plane 5xx, or a request rejected because the label query payload is no longer accepted.","commonSituations":"Expired or missing API key; provider outage; quota exceeded on the account; provider API change altering the expected label-filter request format (leading to 400/422).","solutions":["Check the embedded HTTP status: 401/403 → refresh the cloud API key; 429 → back off and retry; 5xx → retry after the provider recovers.","Retry the listing — it is a read-only call and safe to repeat.","If the status is 400/422, verify the provider still accepts the JSON-encoded exact-match labels filter; update the client if the API contract changed.","Confirm the account has an active subscription/quota; a billed-out account can reject list calls."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify credentials before provider calls\nif std::env::var(\"CODEWHALE_CLOUD_API_KEY\").map_or(true, |k| k.is_empty()) {\n    anyhow::bail!(\"cloud API key not configured\");\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"listing failed (HTTP 40\") => warn_user(\"check cloud credentials\"),\n    Err(e) if e.to_string().contains(\"listing failed\") => retry_with_backoff(list, 2),\n    other => other,\n}","preventionTips":["Keep the cloud API key configured and rotated before expiry.","Treat listing as read-only and safe to retry with backoff.","On 400/422, check whether the provider changed the label-filter contract and update the client.","Monitor account quota so exhausted plans don't break reconciliation passes."],"tags":["http","cloud","listing","api"],"backgroundTag":"http-error-response","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}