{"record":{"id":"747d7928d33b704e","repo":"Hmbown/CodeWhale","slug":"fleet-field-must-be-a-simple-ascii-token-no-long","errorCode":null,"errorMessage":"fleet {field} must be a simple ASCII token no longer than {MAX_FLEET_ID_BYTES} bytes","messagePattern":"fleet (.+?) must be a simple ASCII token no longer than (.+?) bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/task_spec.rs","lineNumber":153,"sourceCode":"        validate_workspace_requirements(task)?;\n    }\n    let mut worker_ids = BTreeSet::new();\n    for worker in &doc.workers {\n        validate_fleet_identity(\"worker id\", &worker.id)?;\n        if !worker_ids.insert(worker.id.clone()) {\n            bail!(\"duplicate fleet worker id {}\", worker.id);\n        }\n        validate_fleet_name(&format!(\"worker {} name\", worker.id), &worker.name)?;\n    }\n    Ok(())\n}\n\nfn validate_fleet_identity(field: &str, value: &str) -> Result<()> {\n    if value.is_empty() {\n        bail!(\"fleet {field} cannot be empty\");\n    }\n    if value.len() > MAX_FLEET_ID_BYTES || !value.chars().all(is_worker_token_char) {\n        bail!(\n            \"fleet {field} must be a simple ASCII token no longer than {MAX_FLEET_ID_BYTES} bytes\"\n        );\n    }\n    Ok(())\n}\n\nfn validate_fleet_name(field: &str, value: &str) -> Result<()> {\n    if value.trim().is_empty() {\n        bail!(\"fleet {field} cannot be empty\");\n    }\n    if value.len() > MAX_FLEET_NAME_BYTES || value.chars().any(char::is_control) {\n        bail!(\n            \"fleet {field} must be one printable line no longer than {MAX_FLEET_NAME_BYTES} bytes\"\n        );\n    }\n    Ok(())\n}\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/fleet/task_spec.rs#L135-L171","documentation":"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.","triggerScenarios":"id = \"{3f2b8c1a-...}\" (braces from a brace-wrapped UUID), id = \"feat/login\" (slash), id = \"task one\" (space), or a slug longer than 128 bytes.","commonSituations":"Copying ids from external trackers (Jira keys with '/', brace-wrapped UUIDs from docs); overlong auto-generated descriptive names; non-ASCII ids from localized teams.","solutions":["Reduce the id to alphanumerics, '-', '_' and '.' (strip braces, slashes, spaces)","Shorten the id to 128 bytes or fewer","Keep the human-readable long form in the name field instead"],"exampleFix":"// before\n{ \"id\": \"{3f2b8c1a-9d2e-4f7a}\" , \"name\": \"x\", \"instructions\": \"...\" }\n\n// after\n{ \"id\": \"3f2b8c1a-9d2e-4f7a\", \"name\": \"x\", \"instructions\": \"...\" }","handlingStrategy":"validation","validationCode":"const MAX_FLEET_ID_BYTES: usize = 128;\nfn is_fleet_id(s: &str) -> bool {\n    !s.is_empty()\n        && s.len() <= MAX_FLEET_ID_BYTES\n        && s.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.'))\n}","typeGuard":"function isFleetId(id: string): boolean {\n  return (\n    id.length > 0 &&\n    id.length <= 128 &&\n    /^[A-Za-z0-9._-]+$/.test(id)\n  );\n}","tryCatchPattern":"if let Err(err) = load_task_spec_document(&path) {\n    if err.to_string().contains(\"simple ASCII token\") {\n        eprintln!(\"{path:?}: ids must be <=128 bytes of [A-Za-z0-9._-] - strip braces/slashes/spaces\");\n    }\n    return Err(err);\n}","preventionTips":["Slugify external ids (strip braces from UUIDs, replace '/' and spaces with '-') before importing them","Keep descriptive text in name; keep id a short slug","Enforce the id regex in spec generators and form inputs"],"tags":["fleet","task-spec","id","identifier","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}