{"record":{"id":"6894147c4477ae9c","repo":"Hmbown/CodeWhale","slug":"sub-agent-session-name-name-is-already-in-use","errorCode":null,"errorMessage":"Sub-agent session name '{name}' is already in use by agent_id '{}' (status: {}, started {since}). Wait for its completion event, or open a new agent with a different name.","messagePattern":"Sub-agent session name '(.+?)' is already in use by agent_id '(.+?)' \\(status: (.+?), started (.+?)\\)\\. Wait for its completion event, or open a new agent with a different name\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":6309,"sourceCode":"        if let Some(name) = options\n            .name\n            .as_deref()\n            .map(str::trim)\n            .filter(|name| !name.is_empty())\n        {\n            if let Some(existing) = self\n                .agents\n                .values()\n                .find(|existing| existing.session_name == name)\n            {\n                // #3020: Include elapsed time so the parent can distinguish a\n                // live worker from a stale/failed earlier spawn (#2656).\n                let elapsed = existing.started_at.elapsed();\n                let since = format!(\n                    \"{} ago\",\n                    crate::elapsed::format_elapsed_secs(elapsed.as_secs())\n                );\n                return Err(anyhow!(\n                    \"Sub-agent session name '{name}' is already in use by agent_id '{}' \\\n                     (status: {}, started {since}). \\\n                     Wait for its completion event, or open a new agent with a different name.\",\n                    existing.id,\n                    subagent_status_name(&existing.status)\n                ));\n            }\n            agent.session_name = name.to_string();\n        }\n        agent.fork_context = options.fork_context;\n        let agent_id = agent.id.clone();\n        let started_at = agent.started_at;\n        let tool_profile = match tools.clone() {\n            Some(tools) => AgentWorkerToolProfile::Explicit(tools),\n            None => AgentWorkerToolProfile::Inherited,\n        };\n        let runtime_profile = match options.preserve_runtime_profile.clone() {\n            Some(preserved) => {","sourceCodeStart":6291,"sourceCodeEnd":6327,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tools/subagent/mod.rs#L6291-L6327","documentation":"Assigning a session_name that another registered agent already holds fails with this error, which names the conflicting agent_id, its current status, and how long ago it started (added so parents can tell a live worker from a stale earlier spawn). Session names must be unique across the manager's registry — the matching does not filter by status, so even a finished agent blocks reuse while its record lives.","triggerScenarios":"Spawning an agent with options.session_name equal to an existing agent's name (e.g., a fixed 'researcher' name in a loop); retry logic re-spawning with the same name after an ambiguous earlier failure; templates that derive names from the task type only, colliding on the second instance.","commonSituations":"Retry/re-spawn loops reusing fixed names; multi-phase workflows naming workers by role ('writer', 'reviewer') where two phases overlap; the earlier stale-spawn ambiguity (#2656) that motivated including elapsed time (#3020) in this message.","solutions":["Make names unique per spawn: suffix with a counter, timestamp, or task id ('writer-3', 'researcher-2026-08-20-2')","Check the existing agent's status first — if it is live, wait for its completion event; if it is stale, it will no longer block once its record is pruned","Reference agents by agent_id from the spawn receipt instead of relying on memorable names"],"exampleFix":"// before\nlet opts = SubAgentSpawnOptions { name: Some(\"researcher\".into()), /* ... */ };\n\n// after\nlet name = format!(\"researcher-{}\", uuid::Uuid::new_v4().simple());\nlet opts = SubAgentSpawnOptions { name: Some(name), /* ... */ };","handlingStrategy":"validation","validationCode":"// Pre-flight name uniqueness before spawn.\nlet taken: Vec<String> = manager.list().into_iter()\n    .filter_map(|s| s.session_name)\n    .collect();\nanyhow::ensure!(!taken.contains(&name),\n    \"session name {name} already taken by a live or recorded agent\");","typeGuard":null,"tryCatchPattern":"On 'already in use', read the embedded agent_id/status/elapsed: if the holder is live, wait for its completion event before reusing the name; otherwise generate a suffixed unique name and retry the spawn once.","preventionTips":["Generate names as role + unique suffix (counter/uuid/timestamp) at the spawn site","Carry agent_ids from spawn receipts as the canonical reference; treat names as display labels only","In retry logic, never respawn with the identical session_name"],"tags":["subagent","rust","naming","duplicate","conflict","spawn"],"backgroundTag":"name-already-in-use","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}