{"record":{"id":"268b19d3c58e1bf0","repo":"Hmbown/CodeWhale","slug":"cloud-dispatch-fails-closed-the-cloud-agent-runs-codewhale","errorCode":null,"errorMessage":"cloud dispatch fails closed: the cloud agent runs Codewhale itself, so it needs a Codewhale account machine token to act as your account. Set CODEWHALE_API_KEY to a `cwc_key_…` machine key (Account → API keys in the web app) and confirm again.","messagePattern":"cloud dispatch fails closed: the cloud agent runs Codewhale itself, so it needs a Codewhale account machine token to act as your account\\. Set CODEWHALE_API_KEY to a `cwc_key_…` machine key \\(Account → API keys in the web app\\) and confirm again\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/cloud_dispatch.rs","lineNumber":1493,"sourceCode":"        api_key: &str,\n        body: serde_json::Value,\n    ) -> Result<reqwest::blocking::Response> {\n        client\n            .request(method, url.clone())\n            .timeout(std::time::Duration::from_secs(total_secs))\n            .bearer_auth(api_key)\n            .json(&body)\n            .send()\n            .context(\"could not reach the cloud agent service\")\n    }\n}\n\nimpl DaytonaLauncher for LiveDaytonaLauncher {\n    fn create_sandbox(&self, job: &CloudJob) -> Result<SandboxReceipt> {\n        let api_key = Self::api_key()?;\n        let url = Self::control_plane_url(\"sandbox\")?;\n        let machine_token =\n            read_cloud_agent_token().ok_or_else(|| anyhow!(missing_machine_token_message()))?;\n        let body = create_sandbox_body(job, &machine_token, &cloud_agent_snapshot());\n        let response = Self::send_json(reqwest::Method::POST, &url, &api_key, body)?;\n        let status = response.status();\n        let text = response.text().unwrap_or_default();\n        if !status.is_success() {\n            bail!(\"Cloud agent create failed (HTTP {status}).\");\n        }\n        let parsed: serde_json::Value =\n            serde_json::from_str(&text).context(\"the cloud agent service returned invalid JSON\")?;\n        let sandbox_id = parsed\n            .get(\"id\")\n            .or_else(|| parsed.get(\"sandboxId\"))\n            .and_then(serde_json::Value::as_str)\n            .unwrap_or(\"\")\n            .trim()\n            .to_string();\n        if !valid_sandbox_id(&sandbox_id) {\n            // The provider says the sandbox exists (2xx) but gave us an id","sourceCodeStart":1475,"sourceCodeEnd":1511,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/cloud_dispatch.rs#L1475-L1511","documentation":"create_sandbox requires a Codewhale account machine token to mint a cloud sandbox that acts as your account; read_cloud_agent_token() returned None, so dispatch fails closed. The message explains the token is distinct from the API key and where to obtain it.","triggerScenarios":"LiveDaytonaLauncher::create_sandbox reaches `read_cloud_agent_token().ok_or_else(...)` after the API key check passes, but no cloud-agent machine token is stored (crates/tui/src/cloud_dispatch.rs:1493).","commonSituations":"User set CODEWHALE_API_KEY but never completed the machine-token provisioning/confirm step, token expired/revoked and removed from storage, or config synced from a machine without the token.","solutions":["Set/provision a `cwc_key_…` machine token as instructed (Account → API keys) and confirm again","Re-run the cloud dispatch confirmation flow to store the token","Check that the token storage location is readable and not cleared between runs","Regenerate the machine key if it was revoked"],"exampleFix":"// before\nread_cloud_agent_token() // None\n// after\nexport CODEWHALE_API_KEY=cwc_key_xxx && re-run dispatch confirm to persist the machine token","handlingStrategy":"validation","validationCode":"let has_token = read_cloud_agent_token().is_some();\nlet has_key = std::env::var(\"CODEWHALE_API_KEY\").is_ok();","typeGuard":null,"tryCatchPattern":"match launcher.create_sandbox(&job) {\n    Err(e) if e.to_string().contains(\"machine token\") => {\n        run_confirm_flow_to_provision_token()?;\n        retry();\n    }\n    other => other?,\n}","preventionTips":["Complete the token provisioning/confirm step after setting the API key","Persist the machine token in the expected store","Regenerate tokens after revocation","Validate both key and token before dispatch"],"tags":["auth","cloud","credentials","token"],"backgroundTag":"missing-credentials","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}