facebook/react · warning
Only one connection allowed at a time. Closing the previous
Error message
Only one connection allowed at a time. Closing the previous connection
What it means
react-devtools-core's standalone entry point (used by the DevTools shell and React Native DevTools) hosts a WebSocket server that supports exactly one active frontend: the module-level `connected` variable holds the single socket. When a new client connects, the previous socket is closed and log.warn prints 'Only one connection allowed at a time. Closing the previous connection'. The behavior is intentional — DevTools is a single-client tool — but the displaced client sees onDisconnected fire and loses its DevTools link.
Source
Thrown at packages/react-devtools-core/src/standalone.js:347
port: number = 8097,
host: string = 'localhost',
httpsOptions?: ServerOptions,
loggerOptions?: LoggerOptions,
path?: string,
clientOptions?: ClientOptions,
): {close(): void} {
registerDevToolsEventLogger(loggerOptions?.surface ?? 'standalone');
const useHttps = !!httpsOptions;
const httpServer = useHttps
? require('https').createServer(httpsOptions)
: require('http').createServer();
const server = new Server({server: httpServer, maxPayload: 1e9});
let connected: WebSocket | null = null;
server.on('connection', (socket: WebSocket) => {
if (connected !== null) {
connected.close();
log.warn(
'Only one connection allowed at a time.',
'Closing the previous connection',
);
}
connected = socket;
socket.onerror = error => {
connected = null;
onDisconnected();
log.error('Error with websocket connection', error);
};
socket.onclose = () => {
connected = null;
onDisconnected();
log('Connection to RN closed');
};
initialize(socket);
});
View on GitHub (pinned to eafeac097b)
Solutions
- Use exactly one DevTools frontend per standalone server: close the previous tab/window before connecting another.
- If you truly need two clients, run a second standalone server on a different port (e.g. react-devtools --port=8098).
- Handle onDisconnected in the embedding app so a takeover is shown in the UI instead of a silently dead panel.
- Make clients close their socket on page unload so stale connections do not hold the slot.
Example fix
# before: two frontends -> one server (first tab gets kicked) npx react-devtools # ws://localhost:8097 # after: one server per client npx react-devtools --port=8097 npx react-devtools --port=8098
Defensive patterns
Strategy: retry
Prevention
- Connect exactly one DevTools frontend per standalone server; close the previous client first.
- Run additional standalone servers on distinct ports for additional clients.
- Close the WebSocket on page unload so stale connections do not occupy the single slot.
- If you are the displaced client, reconnect (with backoff) once the other client disconnects — onDisconnected signals the takeover.
When it happens
Trigger: A second WebSocket client connecting to the standalone server (new Server({server, maxPayload: 1e9})) while a previous one is still registered as `connected`: a second browser tab, a second DevTools shell, or a reconnect that lands before the old socket's onclose cleared the slot.
Common situations: Running `npx react-devtools` and pointing two tabs at the same port; editor-embedded React Native DevTools plus a browser DevTools on the same server; e2e/CI harnesses that leave sockets half-open; rapid reconnect loops.
Related errors
- The should not be any remaining suspense node children if th
- There should always be an Offscreen Fiber child in a hydrate
- Did not expect a host hoistable to be the root
- A dehydrated Suspense node should not have a content Fiber.
- Encountered a dehydrated Suspense boundary that was previous
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/c9bf22579c98fe4c.
Report an issue: GitHub.