deepseek-ai/deepseek-harness · error

sessions.selectSubagent: ${address.childSessionId} is not a

Error message

sessions.selectSubagent: ${address.childSessionId} is not a healthy catalog child

What it means

SessionsManager.selectSubagent re-validates a SubagentAddress against the cached subagent catalog of its parent session before selecting. It throws when no catalog is loaded for address.parentSessionId (so the entry lookup yields undefined), when the child id is absent from catalog.entries, when the entry's kind is not 'child', or when entry.mode differs from address.mode. The guard exists because addresses are durable and catalog-derived: a stale, persisted, or hand-built address must never gain selection authority over the live roster truth.

Source

Thrown at packages/client/runtime/src/client/sessions/manager.ts:212

        ? false
        : this.catalogs.get(address.parentSessionId)?.parentAvailable ?? false,
    )
    this.selected = sessionId
    // Looking at the session consumes its completion reminder (dot clears).
    this.completedNotifications.delete(sessionId)
    void this.refreshSubagents(sessionId)
    this.notifier.notifyNow()
  }

  /**
   * Select a healthy child through its durable direct-parent address.
   * @param address - catalog-derived parent and child ids.
   */
  selectSubagent(address: SubagentAddress): void {
    const catalog = this.catalogs.get(address.parentSessionId)
    const entry = catalog?.entries.find(candidate => candidate.id === address.childSessionId)
    if (entry === undefined || entry.kind !== 'child' || entry.mode !== address.mode) {
      throw new Error(`sessions.selectSubagent: ${address.childSessionId} is not a healthy catalog child`)
    }
    this.addresses.set(address.childSessionId, address)
    this.sessions.get(address.childSessionId)?.configureSubagent(address, catalog?.parentAvailable ?? false)
    this.selected = address.childSessionId
    this.completedNotifications.delete(address.childSessionId)
    void this.refreshSubagents(address.childSessionId)
    this.notifier.notifyNow()
  }

  /** Clear the selection (the layout falls to the no-session view state). */
  clearSelection(): void {
    this.selected = undefined
    this.notifier.notifyNow()
  }

  /**
   * Return the durable catalog address retained for one child.
   * @param sessionId - possible addressed child id.

View on GitHub (pinned to b150a551b8)

Solutions

  1. Re-derive the address from the current catalog, or use manager.select(childSessionId) which resolves a retained or catalog-derived address leniently through navigationAddress and only throws when the session is neither listed nor addressable
  2. Ensure the parent catalog is loaded before offering subagent navigation: open or refresh the parent session first and wait for its catalog pull
  3. Copy the mode field from the catalog entry when constructing the address, never from a constant or persisted string
  4. Invalidate cached addresses on roster/catalog change events and re-read entries before any selection

Example fix

// before — replaying an address captured earlier
manager.selectSubagent(staleAddress)

// after — lenient selection that re-derives the address from loaded catalogs
manager.select(staleAddress.childSessionId)
Defensive patterns

Strategy: try-catch

Try / catch

try {
  manager.selectSubagent(address)
} catch (error) {
  if (error instanceof Error && error.message.startsWith('sessions.selectSubagent:')) {
    // stale address: fall back to lenient selection, which re-derives from loaded catalogs
    manager.select(address.childSessionId)
  } else {
    throw error
  }
}

Prevention

When it happens

Trigger: Calling sessions.openSubagent/selectSubagent with (a) an address captured from an earlier catalog snapshot after the child finished, changed mode, or was removed by a roster change; (b) an address for a parent whose catalog has not been pulled yet (this.catalogs has no entry, so entry is undefined); (c) a mode mismatch, e.g. address.mode 'agent' against entry.mode 'task'; (d) a wrong parentSessionId so the lookup scans another parent's catalog or none.

Common situations: Caching SubagentAddress values across catalog refreshes or page reloads; clicking a subagent row in the same tick a roster change removes it; restoring a persisted address at startup before refreshSubagents has pulled the parent catalog; test fixtures hand-crafting addresses instead of deriving them from catalog entries.

Related errors


AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24). Data as JSON: /api/errors/455f318ed4bf340f. Report an issue: GitHub.