Hmbown/CodeWhale · error
the sandbox id is not a usable path token
Error message
the sandbox id is not a usable path token
What it means
Before interpolating a sandbox id into control-plane or toolbox URL paths, valid_sandbox_id requires a non-empty token of at most 128 chars made of URL-path-safe characters. If the provider (or a stale receipt) returned an id that fails this check, toolbox_base refuses to build a URL rather than risk path injection or a malformed request.
Solutions
- Inspect receipt.sandbox_id — re-create the sandbox so a fresh, provider-issued id replaces the stale one.
- Trim/sanitize the id at the boundary where receipts are produced, or reject it earlier with your own check matching valid_sandbox_id's rules (non-empty, <=128 chars, path-safe).
- If the provider's ids changed format, update the integration rather than bypassing the check.
Example fix
// before
let base = toolbox_base(&receipt)?; // bail on odd id
// after
fn is_path_safe(id: &str) -> bool {
!id.is_empty() && id.len() <= 128 && id.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
}
anyhow::ensure!(is_path_safe(&receipt.sandbox_id), "sandbox id invalid: {:?}", receipt.sandbox_id);
let base = toolbox_base(&receipt)?; Defensive patterns
Strategy: validation
Validate before calling
fn is_path_safe(id: &str) -> bool {
!id.is_empty() && id.len() <= 128 && id.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_'))
}
// before calling any path-building API:
anyhow::ensure!(is_path_safe(&receipt.sandbox_id), "bad sandbox id"); Type guard
fn usable_sandbox_id(id: &str) -> Option<&str> {
if !id.is_empty() && id.len() <= 128 && id.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_')) { Some(id) } else { None }
} Try / catch
match toolbox_base(&receipt) {
Err(e) if e.to_string().contains("not a usable path token") => eprintln!("stale or malformed sandbox id: {:?}", receipt.sandbox_id),
other => other?,
} Prevention
- Validate sandbox ids at receipt creation, not at URL build time.
- Refresh stale receipts from the provider before reuse.
- Mirror valid_sandbox_id's rules wherever ids cross a trust boundary.
When it happens
Trigger: Calling toolbox_base (or any path built from SandboxReceipt.sandbox_id) with a receipt whose sandbox_id is empty, longer than 128 chars, or contains characters like '/', '?', '#', or whitespace.
Common situations: A provider API change altering id format; a stale/corrupted receipt loaded from state; a mock or fake sandbox id used in tests carrying path-special characters.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- --base-url must use http or https
- browser URL cannot be empty
- Codewhale account API base URL must be an origin without a…
- Codewhale account API base URL must not contain a query or…
- Command is required
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/aeebeb339bebd343.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/cloud_dispatch.rs:1421
/// 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")
}
/// Apply the dispatch labels via Daytona's dedicated labels endpoint.
fn put_sandbox_labels(sandbox_id: &str, api_key: &str, job: &CloudJob) -> Result<()> {
if !valid_sandbox_id(sandbox_id) {
bail!("the sandbox id is not a usable path token");
}
let url = Self::control_plane_url(&format!("sandbox/{sandbox_id}/labels"))?;
let body = serde_json::json!({
"labels": {
SANDBOX_JOB_LABEL: job.id,
"codewhale.forge": job.forge.as_str(),
SANDBOX_PRODUCT_LABEL: SANDBOX_PRODUCT_VALUE,View on GitHub (pinned to 73e0f67d83)