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
- Drop all references to the bridge on shutdown; don't send from cleanup paths that may run after teardown.
- Track lifecycle yourself: subscribe to the bridge's 'shutdown' event and set a flag checked before every send.
- 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
- Clear bridge references when the owning component/store is destroyed.
- Listen for the bridge's 'shutdown' event and gate all later calls on it.
- Never share one Bridge across owners with independent lifetimes; create a new Bridge to resume.
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
- Wall.listen() must return an unlisten function.
- Bridge event names must be non-empty strings.
- Invalid renderer id "${rendererID}"
- An unsupported type was passed to use(): ${String(usable)}
- Unknown Fiber. Needs to be a function component to inspect h
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/db37aee6263f407c.
Report an issue: GitHub.