Hmbown/CodeWhale · error

Cloud agent create failed

Error message

Cloud agent create failed (HTTP {status}).

What it means

The POST to Daytona's sandbox create endpoint returned a non-success HTTP status; the response body is discarded (only the status is reported). This is the primary provisioning call for a cloud agent sandbox, so failure means no sandbox exists and the job cannot start.

Solutions

  1. Read the actual HTTP status; if 401/403 re-authenticate or refresh the machine token
  2. Check Daytona quota/billing if 402/429
  3. Retry on 5xx/transient failures
  4. Compare the create body against the current Daytona API if 400
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: require a machine token and api key before attempting create
let token = read_cloud_agent_token().ok_or_else(|| anyhow!("no machine token"))?;
let key = Self::api_key()?;

Try / catch

match create_sandbox(job) {
    Err(e) if e.to_string().contains("HTTP 5") || e.to_string().contains("HTTP 429") => retry_with_backoff(job),
    Err(e) if e.to_string().contains("HTTP 4") => bail!("config/auth problem: {e}"),
    Ok(r) => r,
}

Prevention

When it happens

Trigger: `send_json(POST, url, ...)` returns 401/403 (bad machine token or API key), 400 (invalid create body), 402/quota (out of sandbox credits), 429, or 5xx from Daytona.

Common situations: Missing or expired cloud agent machine token, exhausted Daytona quota/billing, malformed job payload after a protocol change, provider outage.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/9561000704a3a068. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/cloud_dispatch.rs:1499

            .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 id
            // we cannot safely interpolate into a path, so explicit teardown
            // is impossible. Best-effort delete with the raw string when it
            // is at least non-empty (the DELETE path itself validates and
            // will refuse dangerous shapes), and always name it in the
            // error so an operator can clean it up.
            let raw = parsed

View on GitHub (pinned to 73e0f67d83)