Hmbown/CodeWhale · error

duplicate agent profile id {}

Error message

duplicate agent profile id {}

What it means

load_agent_profiles_from_dir loads every *.toml in the profile directory and enforces unique profile ids, compared case-insensitively via to_ascii_lowercase. A second file claiming an already-seen id bails, because worker profiles are addressed by id and a duplicate would make selection ambiguous.

Source

Thrown at crates/tui/src/fleet/profile.rs:287

pub fn load_agent_profile_identities_from_dir(
    dir: impl AsRef<Path>,
) -> Result<Vec<AgentProfileIdentity>> {
    let dir = dir.as_ref();
    agent_profile_paths(dir)?
        .into_iter()
        .map(|path| load_agent_profile_identity_file(&path))
        .collect()
}

pub fn load_agent_profiles_from_dir(dir: impl AsRef<Path>) -> Result<Vec<AgentProfile>> {
    let dir = dir.as_ref();
    let mut profiles = Vec::new();
    let mut seen = BTreeSet::new();
    for path in agent_profile_paths(dir)? {
        let profile = load_agent_profile_file(&path)?;
        if !seen.insert(profile.id.to_ascii_lowercase()) {
            bail!("duplicate agent profile id {}", profile.id);
        }
        profiles.push(profile);
    }
    Ok(profiles)
}

fn agent_profile_paths(dir: &Path) -> Result<Vec<PathBuf>> {
    if !dir.exists() {
        return Ok(Vec::new());
    }
    if !dir.is_dir() {
        bail!("agent profile path {} is not a directory", dir.display());
    }

    let mut paths = std::fs::read_dir(dir)
        .with_context(|| format!("reading agent profile dir {}", dir.display()))?
        .collect::<std::io::Result<Vec<_>>>()
        .with_context(|| format!("reading agent profile entries in {}", dir.display()))?

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. List ids across profile TOMLs in the directory (grep '^id') and rename or remove the duplicate
  2. Remember the check is case-insensitive: 'Coder' and 'coder' collide
  3. Keep one profile per file and name files after their id to prevent recurrence

Example fix

# before: profiles/coder.toml -> id = "coder"; profiles/coder-alt.toml -> id = "Coder"

# after: profiles/coder.toml -> id = "coder"; profiles/reviewer.toml -> id = "reviewer"
Defensive patterns

Strategy: validation

Validate before calling

use std::collections::BTreeSet;

fn profile_ids_unique(paths: &[std::path::PathBuf]) -> Result<(), String> {
    let mut seen = BTreeSet::new();
    for p in paths {
        let id = read_profile_id(p)?; // parse `id = "..."`
        if !seen.insert(id.to_ascii_lowercase()) {
            return Err(format!("duplicate profile id {id} in {}", p.display()));
        }
    }
    Ok(())
}

Try / catch

if let Err(err) = load_agent_profiles_from_dir(&dir) {
    if err.to_string().contains("duplicate agent profile id") {
        eprintln!("two profile TOMLs share an id (case-insensitive); rename one");
    }
    return Err(err.into());
}

Prevention

When it happens

Trigger: Two TOML files in the agent profile dir (including subdirectory-style names differing only by case or extension spelling) whose id fields lowercase to the same value, e.g. "Reviewer" and "reviewer".

Common situations: Copying a profile file to tweak it and forgetting to change id; case-only rename left behind on case-insensitive filesystems; syncing profiles from two machines into one dir.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/d4ee1a0f2db1ef73. Report an issue: GitHub.