Hmbown/CodeWhale · error

cloud job id must look like cloud_

Error message

cloud job id must look like cloud_<hex>

What it means

The cloud job store refuses to build a filesystem path for a job id that does not match the expected shape `cloud_<hex>`. Job ids are used directly as filenames (`<id>.json`), so this check prevents path traversal and malformed ids from reaching the disk before any save or load happens.

Solutions

  1. Print/inspect the id and ensure it matches `cloud_` followed by hexadecimal characters (e.g. `cloud_deadbeef`).
  2. Trim whitespace and strip surrounding quotes/brackets when the id comes from user input, config, or logs.
  3. Obtain the id from the API that created the job (e.g. a DispatchOutcome or the store's own listing) instead of hand-constructing it.
  4. If old records use a legacy id format, migrate or re-create them; the validator is intentionally strict.

Example fix

// before
store.load("abc123")?;
// after
let id = raw_id.trim();
if valid_job_id(id) { store.load(id)?; }
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_job_id(id: &str) -> bool {
    id.starts_with("cloud_") && !id.as_bytes()[6..].is_empty()
        && id[6..].bytes().all(|b| b.is_ascii_hexdigit())
}

Type guard

fn valid_job_id(id: &str) -> bool {
    let hex = id.strip_prefix("cloud_").unwrap_or("");
    !hex.is_empty() && hex.bytes().all(|b| b.is_ascii_hexdigit())
}

Try / catch

match store.load(id) {
    Ok(job) => job,
    Err(e) if e.to_string().contains("cloud_<hex>") => {
        eprintln!("invalid job id '{id}': expected cloud_<hex>");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling CloudJobStore::save or CloudJobStore::load (or higher-level flows that pass through them, e.g. confirm_job) with an id string that is empty, lacks the `cloud_` prefix, or whose suffix is not hexadecimal.

Common situations: Passing a user-typed or clipboard-pasted job id that includes whitespace or a short label; persisting/reusing an id from a different system; parsing an id out of a log line and picking up surrounding text; older persisted records written before the `cloud_` convention was introduced.

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


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

Appendix: source

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

        for entry in fs::read_dir(&self.root).context("failed to read cloud-jobs")? {
            let entry = entry?;
            let name = entry.file_name();
            let name = name.to_string_lossy();
            if !name.starts_with("cloud_") || !name.ends_with(".json") {
                continue;
            }
            let body = fs::read(entry.path())?;
            if let Ok(job) = serde_json::from_slice::<CloudJob>(&body) {
                jobs.push(job);
            }
        }
        jobs.sort_by_key(|a| std::cmp::Reverse(a.created_unix));
        Ok(jobs)
    }

    fn job_path(&self, id: &str) -> Result<PathBuf> {
        if !valid_job_id(id) {
            bail!("cloud job id must look like cloud_<hex>");
        }
        Ok(self.root.join(format!("{id}.json")))
    }
}

/// Classify a git remote. Named `github` / `cnb` / `gitee` win over URL.
pub fn classify_remote(name: &str, url: &str) -> Option<Forge> {
    match name.trim().to_ascii_lowercase().as_str() {
        "github" => Some(Forge::Github),
        "cnb" => Some(Forge::Cnb),
        "gitee" => Some(Forge::Gitee),
        _ => classify_url(url),
    }
}

/// True when `branch` is a forge default that a non-force push could
/// fast-forward past review (`main` / `master` / `HEAD`).
pub fn is_forge_default_branch(branch: &str) -> bool {

View on GitHub (pinned to 73e0f67d83)