Hmbown/CodeWhale · error

Agent continuation target is no longer retained

Error message

Agent continuation target is no longer retained

What it means

Thrown by `continuation_target` when the walk follows a `resume_targets` pointer to a successor id that no longer exists in `self.agents`. The lineage points at a record that was reaped or dropped, so the fork target cannot be established and the operation fails closed rather than silently truncating the chain.

Solutions

  1. Re-check the registry roster and drop stale resume_targets entries pointing at removed agents.
  2. Continue from the last live agent in the chain instead of the dead successor (prune the lineage).
  3. Avoid reusing agent records across registry/session resets; re-spawn the child.
  4. If reaping is concurrent, hold the registry lock for the whole resolve+continue operation.

Example fix

// before
let target = registry.continuation_target(&agent_id)?;
// after
let target = match registry.continuation_target(&agent_id) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("no longer retained") => {
        registry.prune_dead_resume_targets(&agent_id);
        agent_id.to_string() // continue from the last live record
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: fallback

Validate before calling

let mut cur = agent_id.to_string();
while let Some(next) = registry.resume_target_of(&cur) {
    if !registry.contains_agent(&next) {
        anyhow::bail!("lineage successor {next} is not retained");
    }
    cur = next;
}

Try / catch

let target = registry.continuation_target(agent_id).or_else(|_| {
    registry.prune_dead_resume_targets(agent_id);
    Ok(agent_id.to_string()) // continue from the last live record
})?;

Prevention

When it happens

Trigger: Continuing an agent whose resume chain references a successor that was removed from the registry — e.g. the continuation child finished and was reaped, or the registry was reset while old resume_targets entries survived.

Common situations: Holding a reference to a parent across a session switch that rebuilt the registry; concurrent reaping of finished children while another thread continues the parent; stale persisted state loaded into a fresh registry with fewer records.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/cae7a50114938e49. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/subagent/mod.rs:6002

    /// Follow the persisted continuation chain without treating deliberate
    /// `start + resume_from` forks as continuation targets. Every hop retains
    /// the original root conversation; malformed or cyclic state fails closed.
    fn continuation_target(&self, agent_id: &str) -> Result<String> {
        let source = self
            .agents
            .get(agent_id)
            .ok_or_else(|| anyhow!("Agent not found"))?;
        let owner = &source.owner_session_id;
        let mut target = agent_id.to_string();
        let mut seen = HashSet::new();
        while let Some(next) = self.resume_targets.get(&target) {
            if !seen.insert(target.clone()) {
                return Err(anyhow!("Invalid agent continuation lineage: cycle"));
            }
            let successor = self
                .agents
                .get(next)
                .ok_or_else(|| anyhow!("Agent continuation target is no longer retained"))?;
            if owner.is_empty() || successor.owner_session_id != *owner {
                return Err(anyhow!(
                    "Agent continuation target is outside the active session"
                ));
            }
            target.clone_from(next);
        }
        Ok(target)
    }

    fn continuation_source(&self, agent_id: &str) -> Option<String> {
        self.resume_targets.iter().find_map(|(source, target)| {
            (target == agent_id && self.continuation_target(source).is_ok()).then(|| source.clone())
        })
    }

    pub(super) fn continuation_target_for_caller(
        &self,

View on GitHub (pinned to 73e0f67d83)