# How Ego-Lite Handles CDP Session Invalidation When Tabs and Task Spaces Change

> Discover how Ego-Lite invalidates CDP sessions when tabs close or task spaces change. Ensure your automation runtime targets live browser contexts with robust session management.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: internals
- Published: 2026-08-16

---

**Ego-Lite automatically invalidates Chrome DevTools Protocol (CDP) sessions when a browser tab closes, when a CDP command fails with a session-lost error, or when switching between task spaces, ensuring the automation runtime always targets a live browser context.**

The `citrolabs/ego-lite` library manages browser automation through persistent CDP sessions attached to specific tabs. When the underlying target changes or becomes unavailable, the runtime must cleanly discard stale session state to prevent commands from targeting defunct browser contexts. Understanding the session invalidation logic is critical for building resilient automation scripts that recover gracefully from tab closures and task-space transitions.

## Three Conditions That Trigger Session Invalidation

### Target Destruction or Detachment

In [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts), the `handleMessage` function listens for CDP events indicating the current target is no longer valid. Specifically, events of type `Target.detachedFromTarget` or `Target.targetDestroyed` signal that the tab has closed or disconnected. The handler inspects `data.params?.targetId` (or `targetInfo.targetId`) and compares it against `state.sessionTargetId`. If the IDs match, the runtime immediately calls `invalidateSession()` to clear the association (lines 52-66).

### CDP Request Failures

When executing commands through the `browserCdp` helper, the runtime wraps requests in a try-catch block that detects session loss. If the error message matches the `SESSION_LOST` regular expression—`/Session (?:with given id )?not found|Target closed|No session/i`—the code invokes `invalidateSession()`, then automatically obtains a fresh session via `ensureSession()` and retries the original request (lines 95-102).

### Stale Session Detection via TTL

The `ensureSession()` function validates the current session before issuing CDP commands. A session is considered stale if it exceeds `SESSION_TTL_MS` (2000ms) or if the requested `targetId` differs from `state.sessionTargetId`. In either case, `invalidateSession()` runs before the runtime attaches to a new target via `Target.attachToTarget`.

## The invalidateSession() Cleanup Routine

Located at lines 146-154 in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts), the `invalidateSession()` function performs atomic cleanup of session state:

```typescript
export function invalidateSession() {
  if (state.sessionId) {
    pageEnabledSessions.delete(state.sessionId);
    pendingDialogs.delete(state.sessionId);
  }
  state.sessionId = null;
  state.sessionTargetId = null;
  state.sessionAt = 0;
}

```

This routine removes the session ID from tracking maps, clears pending dialog bookkeeping, and resets timestamps stored in [`state.ts`](https://github.com/citrolabs/ego-lite/blob/main/state.ts).

## Task Space Transitions and Session Lifecycle

Task spaces in Ego-Lite are logical containers that encapsulate one or more browser tabs. When a script invokes `taskSpaces.switch()`, `taskSpaces.claim()`, or `taskSpaces.takeOver()` from [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts), these APIs may redirect the automation context to a different tab.

The underlying CDP helpers call `ensureSession()` before executing commands. If the active task space has changed, `ensureSession()` detects the mismatched `targetId` and triggers `invalidateSession()` followed by a fresh `Target.attachToTarget`. This ensures **changing the active task-space automatically forces session invalidation** so subsequent CDP calls target the correct tab.

## Automatic Recovery Example

The runtime's retry mechanism allows scripts to recover transparently from transient session loss:

```javascript
try {
  await cdp('DOM.enable'); // Implicit session injection
} catch (e) {
  // The runtime already called invalidateSession() and retried automatically.
  console.error('Recovered from lost session:', e);
}

```

When switching contexts explicitly:

```javascript
await taskSpaces.switch('research-tab'); // May detach the old target
await elementResolver('loc=css:#login');   // Triggers ensureSession → new session if needed

```

## Summary

- **Target destruction** triggers invalidation via CDP event handlers in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) that monitor `Target.detachedFromTarget` and `Target.targetDestroyed`.
- **Session-lost errors** are caught using the `SESSION_LOST` regex pattern, triggering cleanup and automatic retry logic.
- **TTL expiration** (2 seconds) or target ID mismatches in `ensureSession()` force fresh session attachment.
- **Task-space switches** implicitly invalidate sessions when the underlying `targetId` changes, ensuring CDP commands always reference the current tab.
- The `invalidateSession()` function in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) clears `state.sessionId`, `state.sessionTargetId`, and removes entries from `pageEnabledSessions` and `pendingDialogs`.

## Frequently Asked Questions

### What happens when a browser tab closes while Ego-Lite is connected?

When a tab closes, Chrome emits a `Target.targetDestroyed` or `Target.detachedFromTarget` event. The `handleMessage` function in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) detects this by comparing the event's `targetId` with `state.sessionTargetId` and calls `invalidateSession()` to clear the stale state.

### How does Ego-Lite recover from a lost CDP session during command execution?

If a CDP command throws an error matching the `SESSION_LOST` regex (`/Session (?:with given id )?not found|Target closed|No session/i`), the `browserCdp` catch block invokes `invalidateSession()`, then calls `ensureSession()` to establish a new connection and retries the original request automatically.

### Why does switching task spaces invalidate the CDP session?

Task spaces manage distinct browser tabs. When `taskSpaces.switch()` changes the active context, the underlying `ensureSession()` helper detects a changed `targetId` compared to `state.sessionTargetId`. This mismatch triggers `invalidateSession()` to ensure subsequent CDP commands attach to the correct new tab rather than the previous one.

### Where is session state stored in Ego-Lite?

Mutable session metadata—including `sessionId`, `sessionTargetId`, and timestamps—is maintained in [`state.ts`](https://github.com/citrolabs/ego-lite/blob/main/state.ts). The [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) file contains the logic for `invalidateSession()` and `ensureSession()` that manipulates this state, while [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts) exposes the task-space API that indirectly triggers these updates.