Hmbown/CodeWhale · error
fleet task {task_id} has duplicate tag {tag}
Error message
fleet task {task_id} has duplicate tag {tag} What it means
A fleet task spec was rejected during load because its `tags` array contains the same exact string twice. `validate_tags` (crates/tui/src/fleet/task_spec.rs) walks the tag list and inserts each tag into a BTreeSet; a second identical insert fails. Comparison is exact string equality (only the emptiness check trims), so "api" and " api " are distinct, but "api" twice is a duplicate.
Source
Thrown at crates/tui/src/fleet/task_spec.rs:371
pub fn record_verification_receipt(
ledger: &FleetLedger,
workspace: &Path,
input: &FleetTaskVerificationInput,
verification: FleetTaskVerification,
) -> Result<FleetReceipt> {
let receipt = prepare_verification_receipt(workspace, input, verification)?;
ledger.record_receipt(receipt.clone())?;
Ok(receipt)
}
fn validate_tags(task_id: &str, tags: &[String]) -> Result<()> {
let mut seen = BTreeSet::new();
for tag in tags {
if tag.trim().is_empty() {
bail!("fleet task {task_id} tag cannot be empty");
}
if !seen.insert(tag) {
bail!("fleet task {task_id} has duplicate tag {tag}");
}
}
Ok(())
}
fn validate_workspace_requirements(task: &FleetTaskSpec) -> Result<()> {
let Some(workspace) = &task.workspace else {
return Ok(());
};
let env = workspace.environment.as_ref();
for name in env
.into_iter()
.flat_map(|env| env.required.iter().chain(env.allowlist.iter()))
{
if name.trim().is_empty() {
bail!(
"fleet task {} environment variable name cannot be empty",
task.idView on GitHub (pinned to 0c42157ee5)
Solutions
- Find the task named in the message and delete the repeated tag so each appears once.
- If the spec is generated, deduplicate with a set before serializing: tags.sort(); tags.dedup();
- If you intended two similar tags, note the check is exact-match: differing whitespace/case counts as distinct, so normalize your tag source (trim, lowercase) at generation time instead.
Example fix
# before (fleet task TOML) [[tasks]] id = "audit-1" tags = ["backend", "audit", "backend"] # after [[tasks]] id = "audit-1" tags = ["backend", "audit"]
Defensive patterns
Strategy: validation
Validate before calling
fn check_tags(tags: &[String]) -> Result<(), String> {
let mut seen = std::collections::BTreeSet::new();
for tag in tags {
let t = tag.trim();
if t.is_empty() {
return Err(format!("empty tag: {tag:?}"));
}
if !seen.insert(t) {
return Err(format!("duplicate tag: {tag:?}"));
}
}
Ok(())
} Type guard
fn has_duplicate_tags(tags: &[String]) -> bool {
let mut seen = std::collections::BTreeSet::new();
tags.iter().any(|t| !seen.insert(t.trim()))
} Prevention
- Deduplicate and trim tags at generation time: tags.sort(); tags.dedup();
- Keep tag vocabularies in one shared constant instead of retyping them per task.
- Run a spec lint step (validate_task_spec_document on the parsed doc) in CI before fleet runs.
When it happens
Trigger: A TOML or JSON fleet task document (loaded via `load_task_spec_document`) with e.g. `tags = ["backend", "backend"]` on one task. Also specs generated programmatically that concatenate default tags with user tags without deduplicating.
Common situations: Copy-pasting tag lists between tasks; YAML/TOML anchors or merges that repeat a tag; generators that append a default tag ("fleet", "audit") on top of one the author already wrote.
Related errors
- fleet task {task_id} tag cannot be empty
- fleet task {} environment variable name cannot be empty
- fleet task spec must include at least one task
- 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/bff130af5824f4f3.
Report an issue: GitHub.