facebook/react · error · Error

Cannot ${action} through a Bridge that has been shut down.

Error message

Cannot ${action} through a Bridge that has been shut down.

What it means

The Bridge is single-use: shutdown() sets _isShutdown, emits/sends 'shutdown', removes listeners, detaches from the wall, and flushes the queue. Every public method (addListener, emit, send, and incoming message handling) then calls _assertNotShutdown, which throws 'Cannot <action> through a Bridge that has been shut down.' Using the bridge after teardown is a lifecycle bug in the caller.

Source

Thrown at packages/react-devtools-shared/src/bridge.js:454

    // It is a private method that the bridge ensures is only called at the right times.
    try {
      if (this._messageQueue.length) {
        for (let i = 0; i < this._messageQueue.length; i++) {
          const {event, payload} = this._messageQueue[i];
          this._wall.send(event, payload);
        }
        this._messageQueue.length = 0;
      }
    } finally {
      // We set this at the end in case new messages are added synchronously above.
      // They're already handled so they shouldn't queue more flushes.
      this._scheduledFlush = false;
    }
  };

  _assertNotShutdown(action: string): void {
    if (this._isShutdown) {
      throw new Error(
        `Cannot ${action} through a Bridge that has been shut down.`,
      );
    }
  }

  _handleMessage: (message: mixed) => void = message => {
    // Some Walls share a transport with unrelated messages or legacy DevTools
    // protocols. A message without an event field does not belong to this Bridge.
    if (
      message === null ||
      typeof message !== 'object' ||
      !('event' in message)
    ) {
      return;
    }

    const event = message.event;
    if (typeof event !== 'string' || event.length === 0) {

View on GitHub (pinned to eafeac097b)

Solutions

  1. Drop all references to the bridge on shutdown; don't send from cleanup paths that may run after teardown.
  2. Track lifecycle yourself: subscribe to the bridge's 'shutdown' event and set a flag checked before every send.
  3. If communication must resume, construct a fresh Bridge over a new wall instead of reusing the shut-down one.

Example fix

// before
bridge.shutdown();
// ...later, in an async callback that still holds `bridge`
bridge.send('logElementToConsole', {id});

// after
let isShutdown = false;
bridge.addListener('shutdown', () => { isShutdown = true; });
bridge.shutdown();
// ...later
if (!isShutdown) {
  bridge.send('logElementToConsole', {id});
}
Defensive patterns

Strategy: validation

Validate before calling

let isShutdown = false;
bridge.addListener('shutdown', () => {
  isShutdown = true;
});
// before every use:
if (!isShutdown) bridge.send('myEvent', payload);

Try / catch

try {
  bridge.send('myEvent', payload);
} catch (error) {
  if (/been shut down/.test(error.message)) return; // stale reference after teardown
  throw error;
}

Prevention

When it happens

Trigger: Calling bridge.send(...), bridge.emit(...), or bridge.addListener(...) after bridge.shutdown() returned — e.g. an async operation or component cleanup path that still holds a reference; or a wall message arriving after shutdown (action 'receive a message').

Common situations: Component unmount order races where a late async task sends after DevTools tears down the bridge; reload of an embedded DevTools that shuts down the old bridge while app code keeps sending; multiple owners of the same bridge instance.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/db37aee6263f407c. Report an issue: GitHub.