Hmbown/CodeWhale · error · anyhow::Error
cloud dispatch fails closed: the cloud agent runs Codewhale…
Error message
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.
What it means
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.
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
Example fix
// before read_cloud_agent_token() // None // after export CODEWHALE_API_KEY=cwc_key_xxx && re-run dispatch confirm to persist the machine token
Defensive patterns
Strategy: validation
Validate before calling
let has_token = read_cloud_agent_token().is_some();
let has_key = std::env::var("CODEWHALE_API_KEY").is_ok(); Try / catch
match launcher.create_sandbox(&job) {
Err(e) if e.to_string().contains("machine token") => {
run_confirm_flow_to_provision_token()?;
retry();
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Cloud agents are not available for this account yet; cloud…
- Cloud agents are not available for this account yet; cloud…
- agy OAuth token member
- API key not found. Run 'codewhale auth set --provider '…
- Codex access token in
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/268b19d3c58e1bf0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/cloud_dispatch.rs:1493
api_key: &str,
body: serde_json::Value,
) -> Result<reqwest::blocking::Response> {
client
.request(method, url.clone())
.timeout(std::time::Duration::from_secs(total_secs))
.bearer_auth(api_key)
.json(&body)
.send()
.context("could not reach the cloud agent service")
}
}
impl DaytonaLauncher for LiveDaytonaLauncher {
fn create_sandbox(&self, job: &CloudJob) -> Result<SandboxReceipt> {
let api_key = Self::api_key()?;
let url = Self::control_plane_url("sandbox")?;
let machine_token =
read_cloud_agent_token().ok_or_else(|| anyhow!(missing_machine_token_message()))?;
let body = create_sandbox_body(job, &machine_token, &cloud_agent_snapshot());
let response = Self::send_json(reqwest::Method::POST, &url, &api_key, body)?;
let status = response.status();
let text = response.text().unwrap_or_default();
if !status.is_success() {
bail!("Cloud agent create failed (HTTP {status}).");
}
let parsed: serde_json::Value =
serde_json::from_str(&text).context("the cloud agent service returned invalid JSON")?;
let sandbox_id = parsed
.get("id")
.or_else(|| parsed.get("sandboxId"))
.and_then(serde_json::Value::as_str)
.unwrap_or("")
.trim()
.to_string();
if !valid_sandbox_id(&sandbox_id) {
// The provider says the sandbox exists (2xx) but gave us an idView on GitHub (pinned to 73e0f67d83)