Hmbown/CodeWhale · error
duplicate fleet worker id {}
Error message
duplicate fleet worker id {} What it means
validate_task_spec_document iterates the top-level workers array (also accepted under the legacy alias worker_specs) and bails when a worker id is inserted into a BTreeSet twice. Worker ids address lease assignment and receipts, so duplicates are rejected before the run starts.
Source
Thrown at crates/tui/src/fleet/task_spec.rs:141
}
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()) {
bail!("duplicate fleet worker id {}", worker.id);
}
validate_fleet_name(&format!("worker {} name", worker.id), &worker.name)?;
}
Ok(())
}
fn validate_fleet_identity(field: &str, value: &str) -> Result<()> {
if value.is_empty() {
bail!("fleet {field} cannot be empty");
}
if value.len() > MAX_FLEET_ID_BYTES || !value.chars().all(is_worker_token_char) {
bail!(
"fleet {field} must be a simple ASCII token no longer than {MAX_FLEET_ID_BYTES} bytes"
);
}
Ok(())
}
View on GitHub (pinned to 0c42157ee5)
Solutions
- Find the duplicated worker id from the error and rename one entry
- Give generated workers sequential or role-based ids (builder-1, builder-2)
- When merging spec files, namespace worker ids by their source
Example fix
// before
"workers": [ { "id": "w1", "name": "a" }, { "id": "w1", "name": "b" } ]
// after
"workers": [ { "id": "w1", "name": "a" }, { "id": "w2", "name": "b" } ] Defensive patterns
Strategy: validation
Validate before calling
fn worker_ids_unique(workers: &[FleetWorkerSpec]) -> bool {
let mut seen = std::collections::BTreeSet::new();
workers.iter().all(|w| seen.insert(w.id.as_str()))
} Type guard
function hasUniqueWorkerIds(ws: { id: string }[]): boolean {
return new Set(ws.map((w) => w.id)).size === ws.length;
} Try / catch
if let Err(err) = load_task_spec_document(&path) {
if let Some(id) = err.to_string().strip_prefix("duplicate fleet worker id ") {
eprintln!("worker id '{id}' appears twice in {path:?}");
}
return Err(err);
} Prevention
- Generate worker ids from a counter when scaling worker blocks programmatically
- Remember the legacy worker_specs key maps to the same workers array - check both after migrations
- Namespace worker ids by source when merging specs
When it happens
Trigger: Two entries in the workers array sharing the same "id" field, regardless of their other fields differing.
Common situations: Scaling a spec by copy-pasting a worker block and forgetting to change the id; merging specs from teams that both used "worker-1"; generators emitting a constant id per worker.
Related errors
- duplicate fleet task 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/2388c79bb085ff95.
Report an issue: GitHub.