{"record":{"id":"c9a8d0dc08cefcec","repo":"Hmbown/CodeWhale","slug":"agent-continuation-target-is-outside-the-active-session","errorCode":null,"errorMessage":"Agent continuation target is outside the active session","messagePattern":"Agent continuation target is outside the active session","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":6004,"sourceCode":"    /// the original root conversation; malformed or cyclic state fails closed.\n    fn continuation_target(&self, agent_id: &str) -> Result<String> {\n        let source = self\n            .agents\n            .get(agent_id)\n            .ok_or_else(|| anyhow!(\"Agent not found\"))?;\n        let owner = &source.owner_session_id;\n        let mut target = agent_id.to_string();\n        let mut seen = HashSet::new();\n        while let Some(next) = self.resume_targets.get(&target) {\n            if !seen.insert(target.clone()) {\n                return Err(anyhow!(\"Invalid agent continuation lineage: cycle\"));\n            }\n            let successor = self\n                .agents\n                .get(next)\n                .ok_or_else(|| anyhow!(\"Agent continuation target is no longer retained\"))?;\n            if owner.is_empty() || successor.owner_session_id != *owner {\n                return Err(anyhow!(\n                    \"Agent continuation target is outside the active session\"\n                ));\n            }\n            target.clone_from(next);\n        }\n        Ok(target)\n    }\n\n    fn continuation_source(&self, agent_id: &str) -> Option<String> {\n        self.resume_targets.iter().find_map(|(source, target)| {\n            (target == agent_id && self.continuation_target(source).is_ok()).then(|| source.clone())\n        })\n    }\n\n    pub(super) fn continuation_target_for_caller(\n        &self,\n        active_session_id: &str,\n        agent_ref: &str,","sourceCodeStart":5986,"sourceCodeEnd":6022,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/mod.rs#L5986-L6022","documentation":"Thrown by `continuation_target` when a successor in the resume chain belongs to a different owner session than the source agent (or the source has an empty owner). Continuations may only fork within the active session; crossing sessions would leak conversation state, so the walk refuses.","triggerScenarios":"Calling continue/follow-up for an agent whose `resume_targets` successor has an `owner_session_id` different from the source's owner — e.g. resuming an agent carried over from a previous session — or when the source's owner_session_id is empty.","commonSituations":"Restoring persisted subagent state into a new session and continuing an old lineage; passing an agent id from a detached/foreign session to the active registry; records loaded without owner metadata (empty owner string).","solutions":["Only continue agents that belong to the currently active session; filter the roster by owner_session_id first.","If cross-session continuation is genuinely needed, import the lineage into the active session with a valid owner instead of forking it in place.","Fix data that was loaded with an empty owner_session_id (re-associate the record with the active session).","Spawn a fresh child in the current session carrying the needed context instead of resuming a foreign lineage."],"exampleFix":"// before\nlet outcome = registry.continue_agent(&foreign_agent_id, text)?;\n// after\nif registry.owner_session_of(&foreign_agent_id).as_deref() != Some(active_session_id) {\n    anyhow::bail!(\"agent belongs to another session; spawn a child in this session instead\");\n}\nlet outcome = registry.continue_agent(&foreign_agent_id, text)?;","handlingStrategy":"validation","validationCode":"let owner = registry.owner_session_of(agent_id);\nif owner.as_deref() != Some(active_session_id) {\n    anyhow::bail!(\"agent {agent_id} belongs to session {:?}, not the active session\", owner);\n}","typeGuard":"fn belongs_to_session(owner: &Option<String>, active: &str) -> bool {\n    owner.as_deref() == Some(active) && !active.is_empty()\n}","tryCatchPattern":"match registry.continue_agent(&handle, agent_ref, text, runtime) {\n    Err(e) if e.to_string().contains(\"outside the active session\") => {\n        // spawn a fresh child in this session instead\n        registry.spawn_child_with_context(&text)?;\n    }\n    r => r?,\n}","preventionTips":["Filter the agent roster by owner_session_id before offering continue/follow-up actions.","Never reuse agent ids across session switches.","Ensure restored records always carry a non-empty owner_session_id.","Treat cross-session continuation as unsupported; copy context into a new child."],"tags":["subagent","session-isolation","ownership","rust"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}