Hmbown/CodeWhale · error

fleet {field} must be a simple ASCII token no longer than {M

Error message

fleet {field} must be a simple ASCII token no longer than {MAX_FLEET_ID_BYTES} bytes

What it means

validate_fleet_identity enforces the id grammar for task and worker ids: at most MAX_FLEET_ID_BYTES (128) bytes, and every character must pass is_worker_token_char - ASCII alphanumerics plus '-', '_' and '.'. Ids flow into paths, ledger keys and the wire protocol, so the charset is deliberately strict.

Source

Thrown at crates/tui/src/fleet/task_spec.rs:153

        validate_workspace_requirements(task)?;
    }
    let mut worker_ids = BTreeSet::new();
    for worker in &doc.workers {
        validate_fleet_identity("worker id", &worker.id)?;
        if !worker_ids.insert(worker.id.clone()) {
            bail!("duplicate fleet worker id {}", worker.id);
        }
        validate_fleet_name(&format!("worker {} name", worker.id), &worker.name)?;
    }
    Ok(())
}

fn validate_fleet_identity(field: &str, value: &str) -> Result<()> {
    if value.is_empty() {
        bail!("fleet {field} cannot be empty");
    }
    if value.len() > MAX_FLEET_ID_BYTES || !value.chars().all(is_worker_token_char) {
        bail!(
            "fleet {field} must be a simple ASCII token no longer than {MAX_FLEET_ID_BYTES} bytes"
        );
    }
    Ok(())
}

fn validate_fleet_name(field: &str, value: &str) -> Result<()> {
    if value.trim().is_empty() {
        bail!("fleet {field} cannot be empty");
    }
    if value.len() > MAX_FLEET_NAME_BYTES || value.chars().any(char::is_control) {
        bail!(
            "fleet {field} must be one printable line no longer than {MAX_FLEET_NAME_BYTES} bytes"
        );
    }
    Ok(())
}

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Reduce the id to alphanumerics, '-', '_' and '.' (strip braces, slashes, spaces)
  2. Shorten the id to 128 bytes or fewer
  3. Keep the human-readable long form in the name field instead

Example fix

// before
{ "id": "{3f2b8c1a-9d2e-4f7a}" , "name": "x", "instructions": "..." }

// after
{ "id": "3f2b8c1a-9d2e-4f7a", "name": "x", "instructions": "..." }
Defensive patterns

Strategy: validation

Validate before calling

const MAX_FLEET_ID_BYTES: usize = 128;
fn is_fleet_id(s: &str) -> bool {
    !s.is_empty()
        && s.len() <= MAX_FLEET_ID_BYTES
        && s.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))
}

Type guard

function isFleetId(id: string): boolean {
  return (
    id.length > 0 &&
    id.length <= 128 &&
    /^[A-Za-z0-9._-]+$/.test(id)
  );
}

Try / catch

if let Err(err) = load_task_spec_document(&path) {
    if err.to_string().contains("simple ASCII token") {
        eprintln!("{path:?}: ids must be <=128 bytes of [A-Za-z0-9._-] - strip braces/slashes/spaces");
    }
    return Err(err);
}

Prevention

When it happens

Trigger: id = "{3f2b8c1a-...}" (braces from a brace-wrapped UUID), id = "feat/login" (slash), id = "task one" (space), or a slug longer than 128 bytes.

Common situations: Copying ids from external trackers (Jira keys with '/', brace-wrapped UUIDs from docs); overlong auto-generated descriptive names; non-ASCII ids from localized teams.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/747d7928d33b704e. Report an issue: GitHub.