Skip to content

[Bug] PTY exit handler does not clean up session listeners or Maps — dead sessions accumulate #23

@noahwaldner

Description

@noahwaldner

Severity: High
Category: Memory Leak
File: src/web/server.ts

Description

When a PTY process exits, the exit event handler (line 4711) broadcasts the event and cleans up the respawn controller and timer. It does not remove the session from this.sessions, does not remove its listener closures from this.sessionListenerRefs, and does not clean up associated resources like runSummaryTrackers, subagentWatchers, or transcriptWatchers.

Code

src/web/server.ts:4711–4738:

exit: (code) => {
  // broadcasts...

  // cleans respawn controller ✓
  const controller = this.respawnControllers.get(session.id);
  if (controller) { controller.stop(); ... this.respawnControllers.delete(session.id); }

  // cleans respawn timer ✓
  const timerInfo = this.respawnTimers.get(session.id);
  if (timerInfo) { clearTimeout(timerInfo.timer); ... }

  // nothing below:
  // ✗ this.sessions still holds the session
  // ✗ this.sessionListenerRefs still holds listener closures
  // ✗ this.runSummaryTrackers not cleaned
  // ✗ subagentWatchers / transcriptWatchers not cleaned
},

cleanupSession() handles all of this correctly — but it is only triggered by explicit user deletion or certain error paths, not by natural PTY exit.

Impact

sessionListenerRefs holds closures that capture the full Session object (including up to 2MB terminal buffer). For short-lived auto-sessions that exit without user deletion — such as:

  • Sessions created by scheduled runs
  • One-shot runPrompt sessions
  • Sessions that crash with respawn disabled

…the entire session graph stays in memory indefinitely. Each session that exits without being explicitly deleted adds to permanent heap growth. On a 24-hour autonomous run this can accumulate into hundreds of MB of non-reclaimable memory.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions