Hmbown/CodeWhale · error
duplicate fleet task id {}
Error message
duplicate fleet task id {} What it means
validate_task_spec_document collects task ids into a BTreeSet and bails when an id is inserted twice. Task ids are the join key between tasks, worker assignments, receipts and the ledger, so duplicates are rejected up front rather than resolved silently.
Source
Thrown at crates/tui/src/fleet/task_spec.rs:122
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)?;
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()) {View on GitHub (pinned to 0c42157ee5)
Solutions
- Search the spec for the duplicated id shown in the error and rename one occurrence
- Adopt a naming scheme (feature-area-n) so generated specs cannot collide
- If merging specs, prefix ids with their source spec name
Example fix
// before
{ "tasks": [ { "id": "test", "name": "a", "instructions": "..." },
{ "id": "test", "name": "b", "instructions": "..." } ] }
// after
{ "tasks": [ { "id": "test-api", "name": "a", "instructions": "..." },
{ "id": "test-tui", "name": "b", "instructions": "..." } ] } Defensive patterns
Strategy: validation
Validate before calling
fn task_ids_unique(tasks: &[FleetTaskSpec]) -> bool {
let mut seen = std::collections::BTreeSet::new();
tasks.iter().all(|t| seen.insert(t.id.as_str()))
} Type guard
function hasUniqueIds(tasks: { id: string }[]): boolean {
return new Set(tasks.map((t) => t.id)).size === tasks.length;
} Try / catch
if let Err(err) = load_task_spec_document(&path) {
if let Some(id) = err.to_string().strip_prefix("duplicate fleet task id ") {
eprintln!("task id '{id}' appears twice in {path:?}");
}
return Err(err);
} Prevention
- Derive task ids from a single counter or slug namespace when generating specs
- Namespace ids by source file when merging spec fragments
- De-duplicate ids in a pre-flight check before submitting the fleet run
When it happens
Trigger: Two entries in the tasks array with the same "id" field, e.g. two blocks both reading "id": "implement" after copy-paste.
Common situations: Copy-pasting a task block and editing everything but the id; generators that reset an id counter per section; merging two spec files that each used generic ids like "task-1".
Related errors
- duplicate fleet worker id {}
- fleet task spec must include at least one task
- fleet task {} instructions cannot be empty
- fleet task {} objective cannot be empty
- fleet {field} cannot be empty
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/a8875ad1875a4f44.
Report an issue: GitHub.