vitejs/vite · error · Error
Cannot send non-custom events from the server to the client.
Error message
Cannot send non-custom events from the server to the client.
What it means
Thrown by the server module runner transport's send() (server -> client direction) when the payload type is not 'custom'. The runner transport only forwards custom events from the dev server to the SSR module runner; built-in HMR messages take a different path.
Source
Thrown at packages/vite/src/node/ssr/runtime/serverModuleRunner.ts:126
undefined,
hmrClient,
)
onMessage({ type: 'connected' })
handler = onMessage
},
disconnect() {
if (handler) {
options.channel.api!.outsideEmitter.off('send', handler)
}
options.channel.api!.innerEmitter.emit(
'vite:client:disconnect',
undefined,
hmrClient,
)
},
send(payload) {
if (payload.type !== 'custom') {
throw new Error(
'Cannot send non-custom events from the server to the client.',
)
}
options.channel.api!.innerEmitter.emit(
payload.event,
payload.data,
hmrClient,
)
},
}
}
/**
* Create an instance of the Vite SSR runtime that support HMR.
* @experimental
*/
export function createServerModuleRunner(
environment: DevEnvironment,View on GitHub (pinned to b4d66fee14)
Solutions
- Only send custom events via this transport: send({ type: 'custom', event, data }).
- Use environment.hot.send(...) or the regular HMR channel for built-in payload types.
- If you only need RPC, prefer transport.invoke(...) which is wrapped as a custom vite:invoke event.
Example fix
// before
transport.send({ type: 'update', updates }) // throws
// after
transport.send({ type: 'custom', event: 'my-event', data: updates }) Defensive patterns
Strategy: validation
Validate before calling
// only send custom payloads via the runner transport
transport.send({ type: 'custom', event, data }) Type guard
function isCustomPayload(p: HotPayload): boolean {
return p.type === 'custom'
} Prevention
- Use the regular HMR channel for built-in payload types.
- Reserve the module-runner transport send() for custom events and RPC.
When it happens
Trigger: Server-side code (plugin, framework SSR integration) calling transport.send(payload) with a payload whose type is not 'custom'. The guard is at serverModuleRunner.ts:125.
Common situations: A plugin trying to broadcast an 'update'/'connected' payload to the SSR runner through the module-runner transport instead of the regular HMR channel. Misuse of the transport's send for built-in HMR orchestration.
Related errors
- Cannot send non-custom events from the client to the server.
- HMR is not supported by this runner transport, but `hmr` opt
- Module "${url}" was mistakenly invalidated during fetch phas
- [module runner] Failed to load "${url}"${importer ? ` import
- [module runner] Dynamic access of "import.meta.env" is not s
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/66f94e0bf3981c3f.
Report an issue: GitHub.