Hmbown/CodeWhale · error
fleet task spec must include at least one task
Error message
fleet task spec must include at least one task
What it means
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.
Source
Thrown at crates/tui/src/fleet/task_spec.rs:116
.file_stem()
.and_then(|s| s.to_str())
.filter(|s| !s.is_empty())
.unwrap_or("fleet-run")
.to_string();
let parsed = match path.extension().and_then(|s| s.to_str()) {
Some("toml") => toml::from_str::<FleetTaskSpecFile>(&raw)
.with_context(|| format!("parsing TOML fleet task spec {}", path.display()))?,
_ => serde_json::from_str::<FleetTaskSpecFile>(&raw)
.with_context(|| format!("parsing JSON fleet task spec {}", path.display()))?,
};
let doc = parsed.into_document(fallback_name);
validate_task_spec_document(&doc)?;
Ok(doc)
}
pub fn validate_task_spec_document(doc: &FleetTaskSpecDocument) -> Result<()> {
if doc.tasks.is_empty() {
bail!("fleet task spec must include at least one task");
}
let mut ids = BTreeSet::new();
for task in &doc.tasks {
validate_fleet_identity("task id", &task.id)?;
if !ids.insert(task.id.clone()) {
bail!("duplicate fleet task id {}", task.id);
}
validate_fleet_name(&format!("task {} name", task.id), &task.name)?;
if task.instructions.trim().is_empty() {
bail!("fleet task {} instructions cannot be empty", task.id);
}
if let Some(objective) = &task.objective
&& objective.trim().is_empty()
{
bail!("fleet task {} objective cannot be empty", task.id);
}
validate_worker_profile(&task.id, task.worker.as_ref())?;
validate_tags(&task.id, &task.tags)?;View on GitHub (pinned to 0c42157ee5)
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
Example fix
// before
{ "name": "run", "workers": [{ "id": "w1", "name": "w1" }] }
// after
{
"name": "run",
"workers": [{ "id": "w1", "name": "w1" }],
"tasks": [{ "id": "t1", "name": "t1", "instructions": "Run the suite" }]
} Defensive patterns
Strategy: validation
Validate before calling
// after parsing, before starting the run:
if doc.tasks.is_empty() {
return Err(anyhow!("fleet task spec must include at least one task"));
} Type guard
// TypeScript, when authoring specs:
function hasTasks(v: unknown): v is { tasks: unknown[] } {
return (
!!v && typeof v === "object" && Array.isArray((v as any).tasks) &&
(v as any).tasks.length > 0
);
} Try / catch
if let Err(err) = load_task_spec_document(&path) {
if err.to_string().contains("at least one task") {
eprintln!("{path:?} has no tasks - add one or use the bare-array form");
}
return Err(err);
} Prevention
- 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
When it happens
Trigger: A JSON spec {"workers":[...]} with no tasks key; {"tasks":[]}; a TOML spec with tasks = []; a YAML-to-JSON conversion that dropped the tasks array.
Common situations: Drafting a spec workers-first and forgetting tasks; templates with a placeholder empty array; scripts that emit the document skeleton before tasks are generated.
Related errors
- agent profile {} {field} cannot be empty
- agent profile {} {field} must be a simple token
- agent profile {} provider cannot be empty
- duplicate fleet task id {}
- fleet task {} instructions cannot be empty
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/38b8e9095a16db3d.
Report an issue: GitHub.