Skip to content

fix(host-api): tear down subscriptions on transport disposal#196

Merged
johnthecat merged 26 commits into
mainfrom
fix/transport-dispose-subscription-leak
Jun 3, 2026
Merged

fix(host-api): tear down subscriptions on transport disposal#196
johnthecat merged 26 commits into
mainfrom
fix/transport-dispose-subscription-leak

Conversation

@cuteWarmFrog

Copy link
Copy Markdown
Contributor

Description

Fixes the uncaught Error: Transport is disposed thrown from a subscription producer after a transport is destroyed (seen in Sentry when a product/container is closed — e.g. statement-store flush after navigating away).

handleSubscription tracks each producer's unsubscribe per requestId, but only runs them via the cleanup it returns. transport.destroy() never calls that cleanup, and host-container's subscription slot discards it. So a disposed transport leaves producers running; their next (often batched/async) emission calls send()postMessage()throwIfDisposed() and throws, unhandled.

Changes Made

In packages/host-api/src/transport.ts, handleSubscription:

  • Drain on destroy: register the existing teardown via transport.onDestroy(...), so destroy() tears down every active producer subscription regardless of what the caller does with the returned cleanup. The returned cleanup also unregisters the destroy listener.
  • No-op late emissions: guard the receive/interrupt callbacks with the disposed flag, so an emission already queued at the moment of disposal is dropped silently instead of throwing.
  • Avoid double-unsub: the stop handler now deletes its map entry, so a subscription that was already stopped isn't unsubscribed again when destroy() drains the map.

One place, fixes every consumer (statement-store, theme, accounts, preimage, chat, payments).

Tests

Added two tests in transport.spec.ts:

  • destroy() runs the producer's unsubscribe.
  • a producer emission after destroy() does not throw and is not delivered.

Both fail on the current code and pass with this change.

Verification

  • nx typecheck host-api: pass
  • nx lint host-api: 0 errors (pre-existing any warnings only)
  • host-api/transport.spec.ts: 9/9 pass

Note: 3 tests in __tests__/hostApi/theme.spec.ts fail on the clean release/0.8 tip (the published 0.8.0 commit) independent of this change — pre-existing, unrelated to this fix.


🤖 Generated with Claude Code

kalininilya and others added 23 commits May 22, 2026 14:36
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
handleSubscription tracked each producer's unsubscribe per requestId but
only ran them via the cleanup it returned. transport.destroy() never called
that cleanup, and host-container's subscription slot discards it — so a
disposed transport left producers running. Their next (often batched/async)
emission called send() -> postMessage() -> throwIfDisposed(), throwing an
uncaught 'Transport is disposed' (seen in Sentry on product close).

- Register the teardown via transport.onDestroy so destroy() drains every
  active producer subscription, regardless of what the caller does with the
  returned cleanup.
- Guard the receive/interrupt callbacks with the disposed flag so an emission
  already queued at disposal is dropped silently instead of throwing.
- stop handler now deletes its map entry so destroy() can't double-unsub a
  subscription that was already stopped.
@cuteWarmFrog

Copy link
Copy Markdown
Contributor Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@cuteWarmFrog cuteWarmFrog self-assigned this Jun 2, 2026
@cuteWarmFrog cuteWarmFrog requested a review from johnthecat June 2, 2026 13:22
@johnthecat johnthecat changed the base branch from release/0.8 to main June 2, 2026 18:33
Comment thread packages/host-api/src/transport.ts
@cuteWarmFrog cuteWarmFrog requested a review from johnthecat June 3, 2026 08:35
@johnthecat johnthecat merged commit 055b4fe into main Jun 3, 2026
5 checks passed
@johnthecat johnthecat deleted the fix/transport-dispose-subscription-leak branch June 11, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants