{"record":{"id":"7a4881174dcc72c2","repo":"Hmbown/CodeWhale","slug":"agent-session-name-agent-ref-is-ambiguous-use","errorCode":null,"errorMessage":"Agent session name '{agent_ref}' is ambiguous; use an agent_id","messagePattern":"Agent session name '(.+?)' is ambiguous; use an agent_id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":6748,"sourceCode":"        {\n            return Ok(agent.id.clone());\n        }\n\n        let matches = self\n            .agents\n            .values()\n            .filter(|agent| agent.session_name == agent_ref)\n            .filter(|agent| {\n                active_session_id\n                    .is_none_or(|session_id| self.agent_is_owned_by_session(agent, session_id))\n            })\n            .map(|agent| agent.id.clone())\n            .collect::<Vec<_>>();\n\n        match matches.as_slice() {\n            [id] => Ok(id.clone()),\n            [] => Err(anyhow!(\"Agent session {agent_ref} not found\")),\n            _ => Err(anyhow!(\n                \"Agent session name '{agent_ref}' is ambiguous; use an agent_id\"\n            )),\n        }\n    }\n\n    fn agent_is_owned_by_session(&self, agent: &SubAgent, active_session_id: &str) -> bool {\n        !active_session_id.is_empty() && agent.owner_session_id == active_session_id\n    }\n\n    fn agent_id_is_owned_by_session(&self, agent_id: &str, active_session_id: &str) -> bool {\n        self.agents\n            .get(agent_id)\n            .is_some_and(|agent| self.agent_is_owned_by_session(agent, active_session_id))\n    }\n\n    /// Resolve a hierarchy mutation target and prove that it is a strict\n    /// descendant of the calling agent. Root registries carry no caller id\n    /// (or the literal `root`) and retain authority over every child. This","sourceCodeStart":6730,"sourceCodeEnd":6766,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tools/subagent/mod.rs#L6730-L6766","documentation":"Session-name resolution found two or more agents sharing the referenced session_name (within the active session's owned agents, when a filter is applied), so it refuses to guess and demands the unique agent_id. Duplicate names across the registry arise when name uniqueness was only enforced within one scope — e.g., the same name registered in different sessions and resolved globally, or legacy/imported state predating the duplicate check.","triggerScenarios":"resolve_agent_ref on a name that matches multiple agents (global resolution with no active_session_id); two sessions each owning a 'writer' agent and resolution running without a session filter; state restored from older versions that permitted duplicate names.","commonSituations":"Role-based naming ('writer', 'reviewer') reused across parallel sessions; cross-session resume or imported history creating registry overlap; global tool calls that predate session-scoped routing.","solutions":["Pass the explicit agent_id (from the spawn receipt or manager.list()) instead of the ambiguous name","Narrow the resolution scope: use the *_for_session variants so only the active session's agents match","Adopt unique name generation (role + counter/uuid) so collisions cannot occur even across sessions"],"exampleFix":"// before\nlet id = manager.followup_child(&\"writer\", text)?; // ambiguous\n\n// after\nlet matches: Vec<String> = manager.list().into_iter()\n    .filter(|s| s.session_name.as_deref() == Some(\"writer\"))\n    .map(|s| s.agent_id)\n    .collect();\nanyhow::ensure!(matches.len() == 1,\n    \"name 'writer' matches {} agents; pass an explicit agent_id\", matches.len());\nlet receipt = manager.followup_child(&matches[0], text)?;","handlingStrategy":"validation","validationCode":"// Count matches up front and disambiguate explicitly.\nlet matches: Vec<String> = manager.list().into_iter()\n    .filter(|s| s.session_name.as_deref() == Some(agent_ref.trim()))\n    .map(|s| s.agent_id)\n    .collect();\nif matches.len() > 1 {\n    return Err(anyhow::!(\n        \"name {agent_ref} is ambiguous across {} agents; pass one of {matches:?}\",\n        matches.len()\n    ));\n}","typeGuard":null,"tryCatchPattern":"Catch 'is ambiguous; use an agent_id', enumerate the candidates from list() (id + status + owner session), and re-issue the call with the explicit id — often after asking the user/model to pick based on status.","preventionTips":["Make session names globally unique by construction (role + session/task suffix)","Use session-scoped resolution APIs so cross-session duplicates cannot collide","Default tooling to agent_ids and keep names for display only"],"tags":["subagent","rust","name-resolution","ambiguity","duplicate-names"],"backgroundTag":"ambiguous-identifier","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}