{"record":{"id":"38b8e9095a16db3d","repo":"Hmbown/CodeWhale","slug":"fleet-task-spec-must-include-at-least-one-task","errorCode":null,"errorMessage":"fleet task spec must include at least one task","messagePattern":"fleet task spec must include at least one task","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/task_spec.rs","lineNumber":116,"sourceCode":"        .file_stem()\n        .and_then(|s| s.to_str())\n        .filter(|s| !s.is_empty())\n        .unwrap_or(\"fleet-run\")\n        .to_string();\n    let parsed = match path.extension().and_then(|s| s.to_str()) {\n        Some(\"toml\") => toml::from_str::<FleetTaskSpecFile>(&raw)\n            .with_context(|| format!(\"parsing TOML fleet task spec {}\", path.display()))?,\n        _ => serde_json::from_str::<FleetTaskSpecFile>(&raw)\n            .with_context(|| format!(\"parsing JSON fleet task spec {}\", path.display()))?,\n    };\n    let doc = parsed.into_document(fallback_name);\n    validate_task_spec_document(&doc)?;\n    Ok(doc)\n}\n\npub fn validate_task_spec_document(doc: &FleetTaskSpecDocument) -> Result<()> {\n    if doc.tasks.is_empty() {\n        bail!(\"fleet task spec must include at least one task\");\n    }\n    let mut ids = BTreeSet::new();\n    for task in &doc.tasks {\n        validate_fleet_identity(\"task id\", &task.id)?;\n        if !ids.insert(task.id.clone()) {\n            bail!(\"duplicate fleet task id {}\", task.id);\n        }\n        validate_fleet_name(&format!(\"task {} name\", task.id), &task.name)?;\n        if task.instructions.trim().is_empty() {\n            bail!(\"fleet task {} instructions cannot be empty\", task.id);\n        }\n        if let Some(objective) = &task.objective\n            && objective.trim().is_empty()\n        {\n            bail!(\"fleet task {} objective cannot be empty\", task.id);\n        }\n        validate_worker_profile(&task.id, task.worker.as_ref())?;\n        validate_tags(&task.id, &task.tags)?;","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/fleet/task_spec.rs#L98-L134","documentation":"load_task_spec_document accepts three shapes: a full document with a tasks array, a bare JSON array of tasks, or a single task object. validate_task_spec_document then requires at least one task; tasks is serde-defaulted to an empty Vec, so a document that omits it or sets tasks = [] fails here. A fleet run with zero tasks is meaningless, so the spec is rejected before any worker spawns.","triggerScenarios":"A JSON spec {\"workers\":[...]} with no tasks key; {\"tasks\":[]}; a TOML spec with tasks = []; a YAML-to-JSON conversion that dropped the tasks array.","commonSituations":"Drafting a spec workers-first and forgetting tasks; templates with a placeholder empty array; scripts that emit the document skeleton before tasks are generated.","solutions":["Add at least one task object to the tasks array with id, name and instructions","If you meant a single task, the bare-array or single-object forms also satisfy the check","Verify with a JSON/TOML linter that the tasks key survived your pipeline"],"exampleFix":"// before\n{ \"name\": \"run\", \"workers\": [{ \"id\": \"w1\", \"name\": \"w1\" }] }\n\n// after\n{\n  \"name\": \"run\",\n  \"workers\": [{ \"id\": \"w1\", \"name\": \"w1\" }],\n  \"tasks\": [{ \"id\": \"t1\", \"name\": \"t1\", \"instructions\": \"Run the suite\" }]\n}","handlingStrategy":"validation","validationCode":"// after parsing, before starting the run:\nif doc.tasks.is_empty() {\n    return Err(anyhow!(\"fleet task spec must include at least one task\"));\n}","typeGuard":"// TypeScript, when authoring specs:\nfunction hasTasks(v: unknown): v is { tasks: unknown[] } {\n  return (\n    !!v && typeof v === \"object\" && Array.isArray((v as any).tasks) &&\n    (v as any).tasks.length > 0\n  );\n}","tryCatchPattern":"if let Err(err) = load_task_spec_document(&path) {\n    if err.to_string().contains(\"at least one task\") {\n        eprintln!(\"{path:?} has no tasks - add one or use the bare-array form\");\n    }\n    return Err(err);\n}","preventionTips":["Make spec templates fail to render when the tasks array is empty","Prefer the bare task-array JSON form for single-task runs so an empty document cannot occur","Run validate_task_spec_document on generated specs in CI"],"tags":["fleet","task-spec","json","toml","validation"],"backgroundTag":"empty-required-collection","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}