{"record":{"id":"aeb0bc07f8248ea2","repo":"Hmbown/CodeWhale","slug":"fleet-field-cannot-be-empty","errorCode":null,"errorMessage":"fleet {field} cannot be empty","messagePattern":"fleet (.+?) cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/task_spec.rs","lineNumber":150,"sourceCode":"        }\n        validate_worker_profile(&task.id, task.worker.as_ref())?;\n        validate_tags(&task.id, &task.tags)?;\n        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    }","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/fleet/task_spec.rs#L132-L168","documentation":"validate_fleet_identity is applied to every task id and worker id and rejects an empty string. Ids are filesystem- and ledger-facing keys, so a blank one can never be valid.","triggerScenarios":"A task or workers entry with \"id\": \"\" - the very first check in validate_fleet_identity fires before format or length checks.","commonSituations":"A generator emitting an empty id before assigning one; hand-editing that removed the id text; JSON built from a map with a blank key.","solutions":["Set a non-empty id on the entry named by the field prefix in the error (\"task id\" or \"worker id\")","Fail template expansion when an id variable is empty","Use the same slug everywhere for the logical unit so ids stay greppable"],"exampleFix":"// before\n{ \"id\": \"\", \"name\": \"build\", \"instructions\": \"...\" }\n\n// after\n{ \"id\": \"build\", \"name\": \"build\", \"instructions\": \"...\" }","handlingStrategy":"validation","validationCode":"fn ids_nonempty(entries: &[impl AsRef<str>]) -> bool {\n    entries.iter().all(|e| !e.as_ref().is_empty())\n}","typeGuard":"function isNonEmptyId(id: string): boolean {\n  return id.length > 0;\n}","tryCatchPattern":"if let Err(err) = load_task_spec_document(&path) {\n    if err.to_string().contains(\"cannot be empty\") {\n        eprintln!(\"{path:?}: every task/worker entry needs a non-empty id\");\n    }\n    return Err(err);\n}","preventionTips":["Fail spec generation when an id variable resolves to empty","Default generated ids to a slug of the task name as a safety net","Validate ids at authoring time, not just at fleet launch"],"tags":["fleet","task-spec","id","validation","required-field"],"backgroundTag":"empty-required-field","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}