Hmbown/CodeWhale · error · anyhow::Error
Cloud agents are not available for this account yet; cloud…
Error message
Cloud agents are not available for this account yet; cloud dispatch fails closed (no sandbox, no push, no PR). | Cloud agents are included with your Codewhale membership. Sign in with `codewhale login` to enable `/dispatch`; cloud dispatch fails closed until then (no sandbox, no push, no PR).
What it means
Cloud dispatch refuses to run because Codewhale account credentials are missing: `api_key()` calls `read_api_key()` and, when absent, fails with `missing_credentials_message()`. That message states cloud agents are included with a Codewhale membership and that dispatch fails closed — no sandbox, no push, no PR — until the user signs in with `codewhale login`. The failure is deliberate: cloud dispatch must never run unauthenticated.
Solutions
- Run `codewhale login` to authenticate and store the API key
- Verify the credential file exists in the Codewhale home (`CODEWHALE_HOME` / user home)
- Set a valid API key if the credential reader supports environment fallback
- Re-run `/dispatch` after authenticating
Example fix
# before $ codewhale # then /dispatch -> fails closed # after $ codewhale login $ codewhale # then /dispatch -> proceeds
Defensive patterns
Strategy: validation
Validate before calling
# check credentials before dispatch
if not codewhale_logged_in():
raise SystemExit("Run 'codewhale login' before /dispatch") Type guard
fn can_dispatch() -> bool { read_api_key().is_some() } Try / catch
if let Err(e) = dispatch(job).await {
if e.to_string().contains("fails closed") {
eprintln!("Not signed in. Run: codewhale login");
return;
}
return Err(e);
} Prevention
- Run `codewhale login` on every new machine/container
- Check credential presence before starting dispatch workflows
- Re-authenticate after credential rotation or expiry
- Ensure CI/containers mount or provision the credential store
When it happens
Trigger: Invoking `/dispatch` (or `execute_dispatch`/`confirm_job`) without a stored API key: never having run `codewhale login`, credentials deleted/expired from local storage, or running in an environment without the saved auth state.
Common situations: Fresh machine install before login; CI or container environments lacking the credential store; corrupted or cleared config directory; expired stored session removed by the credential reader.
Related errors
- Cloud agents are not available for this account yet; cloud…
- cloud dispatch fails closed: the cloud agent runs Codewhale…
- API key not found. Run 'codewhale auth set --provider '…
- DeepSeek API key not found. 1. Get a key: …
- external credential access for
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/799004dc878ad5b7.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/cloud_dispatch.rs:1408
/// A client scoped to one harness command: its total timeout is the
/// command's declared budget plus fixed slack. The declared turn budget
/// is an hour, so the 120s control-plane cap must NOT carry this call —
/// otherwise every dispatched turn longer than two minutes fails after
/// the spend has already started.
fn harness_client(command: &HarnessCommand) -> Result<reqwest::blocking::Client> {
Self::blocking_client_with_timeout(Self::harness_client_budget_secs(command))
}
/// The total-timeout budget for a harness-carrying client, in seconds.
/// Public to the crate so the runner's tests can pin it against the
/// declared `HARNESS_TIMEOUT_SECS`.
pub(crate) fn harness_client_budget_secs(command: &HarnessCommand) -> u64 {
u64::from(command.timeout_secs).saturating_add(Self::HARNESS_CLIENT_SLACK_SECS)
}
fn api_key() -> Result<String> {
read_api_key().ok_or_else(|| anyhow!(missing_credentials_message()))
}
/// Control-plane URL under the validated base.
fn control_plane_url(path: &str) -> Result<reqwest::Url> {
let base = validate_outbound_origin(&daytona_api_url())?;
join_api_path(base, path).context("failed to build the cloud agent request URL")
}
/// Toolbox base for one sandbox: `{toolboxProxyUrl}/{sandboxId}`.
fn toolbox_base(receipt: &SandboxReceipt) -> Result<reqwest::Url> {
if !valid_sandbox_id(&receipt.sandbox_id) {
bail!("the sandbox id is not a usable path token");
}
let fallback = format!("{}/toolbox", DEFAULT_DAYTONA_API);
let raw = receipt.toolbox_url.as_deref().unwrap_or(&fallback);
let base = validate_outbound_origin(raw)?;
join_api_path(base, &receipt.sandbox_id).context("failed to build the sandbox toolbox URL")
}View on GitHub (pinned to 433685b202)