vitejs/vite · error · Error
client ID conflict detected. Please restart the dev server.
Error message
client ID conflict detected. Please restart the dev server.
What it means
Clients.setupIfNeeded maps a hot channel client to its clientId. If the same client object is already registered with a different id, Vite throws because the client identity and the id are out of sync — usually a symptom of a stale/HMR-desynced connection. The message asks the user to restart the dev server.
Solutions
- Restart the dev server as the message suggests.
- Hard-reload the browser tab to drop stale HMR client state.
- If using a custom transport, ensure each new clientId is paired with a new client object (or call delete on the old mapping).
- Update Vite — this is often a transient HMR desync fixed in newer patches.
Example fix
// before — custom transport reuses client object with new id
client.emit('vite:client-connected', { clientId: newId })
// after — drop the old mapping first
clients.delete(oldClient)
client.emit('vite:client-connected', { clientId: newId }) Defensive patterns
Strategy: validation
Validate before calling
// For custom transports, ensure clientId mapping is unique
function assertNoClientIdConflict(clients, client, clientId) {
const existing = clients.getId(client)
if (existing && existing !== clientId) throw new Error('client ID conflict; restart dev server')
} Try / catch
try {
clients.setupIfNeeded(client, clientId)
} catch (e) {
if (/client ID conflict/.test(e.message)) { await server.restart() }
throw e
} Prevention
- Pair each new clientId with a fresh client object or delete the old mapping.
- Restart the dev server when HMR behaves erratically.
- Hard-reload the browser tab to reset HMR client state.
When it happens
Trigger: A hot channel client reconnects (vite:client-connected / vite:client:connect) and presents a clientId that differs from the one previously bound to the same underlying transport client. Happens when HMR state diverges from the server's client map.
Common situations: Long-lived dev sessions with aggressive HMR, custom transports/proxies that reuse connection objects, or bugs in the HMR client that regenerate ids without dropping the old mapping.
Related errors
- Cannot send non-custom events from the client to the server.
- Cannot send non-custom events from the server to the client.
- HMR is not supported by this runner transport, but `hmr`…
- Cannot call server.listen in middleware mode.
- Cannot print server URLs before server.listen is called.
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/cfb8664cf115b6d4.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/server/bundledDev.ts:502
if (truncated) debugHmr?.(`hmr update ${hmrOutput.changedIds.join(', ')}`)
this.environment.logger.info(
colors.green(`hmr update `) + colors.dim(formatted),
{
clear: true,
timestamp: true,
},
)
}
}
class Clients {
private clientToId = new Map<NormalizedHotChannelClient, string>()
private idToClient = new Map<string, NormalizedHotChannelClient>()
setupIfNeeded(client: NormalizedHotChannelClient, clientId: string) {
const id = this.clientToId.get(client)
if (id && id !== clientId) {
throw new Error(
'client ID conflict detected. Please restart the dev server.',
)
}
this.clientToId.set(client, clientId)
this.idToClient.set(clientId, client)
}
get(id: string): NormalizedHotChannelClient | undefined {
return this.idToClient.get(id)
}
getId(client: NormalizedHotChannelClient): string | undefined {
return this.clientToId.get(client)
}
getAll(): NormalizedHotChannelClient[] {
return Array.from(this.idToClient.values())
}View on GitHub (pinned to b4d66fee14)