Skip to content

Unhandled Error: Not connected rejection when AppRenderer sends host-context-change to a torn-down sandbox #208

Description

@KlaasHulder

Package: @mcp-ui/client@7.1.1

Summary

AppRenderer emits an unhandled promise rejectionError: Not connected — when it sends a host-context-change notification to a sandbox iframe whose transport has already been torn down. Because the send is fire-and-forget (not awaited/caught), the rejection escapes any onError handling and reaches the browser's global unhandledrejection handler, so it surfaces in the console and in error-tracking tools (Sentry, etc.).

The card itself renders fine — this is a benign teardown race, but it produces persistent noise in production error monitoring.

Conditions

The host re-renders frequently (e.g. an LLM chat streaming responses), which rebuilds the bridge, and the user can disconnect/reconnect or navigate away. When a setHostContext fires around the moment the transport closes (unmount / disconnect / bridge rebuild), the notification is sent over a closed transport.

Stack signature (minified, production build)

Error: Not connected
  <transport>.notification
  <bridge>.sendHostContextChange
  <bridge>.setHostContext
  mechanism: onunhandledrejection, handled: no

(The setHostContext → sendHostContextChange → notification chain is the tell.)

Expected

Pushing a host-context update to an already-closed / not-yet-connected transport should not produce an unhandled rejection. Either:

  • guard the send (if (transport.connected) …), or
  • swallow/catch the Not connected rejection internally (it is non-actionable for the host), or
  • surface it through the component's onError callback instead of the global handler,

so hosts don't have to filter it out at the Sentry/console layer.

Workaround (host side)

We currently drop it in our Sentry beforeSend and preventDefault() it in an unhandledrejection listener, matched narrowly on message === "Not connected" + the onunhandledrejection mechanism. Would prefer not to string-match a third-party message long-term.

Environment

  • @mcp-ui/client 7.1.1
  • React 19, Next.js (App Router), Chrome
  • AppRenderer with a separate-origin sandbox proxy

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions