vitejs/vite · error · Error
transport must implement send and connect when invoke is…
Error message
transport must implement send and connect when invoke is not implemented
What it means
Thrown when normalizing a ModuleRunnerTransport that defines neither invoke nor both send+connect. The transport contract requires either an invoke method (direct RPC) or a send+connect pair (so Vite can synthesize invoke over the message channel); providing only one of send/connect, or neither, is invalid.
Solutions
- Provide invoke on the transport if you handle RPC yourself.
- Otherwise provide both connect(handlers) and send(payload) — the pair is required to synthesize invoke.
- Use createWebSocketModuleRunnerTransport as the template; it correctly implements connect+disconnect+send.
Example fix
// before
const transport = { send(payload) { ws.send(JSON.stringify(payload)) } } // missing connect -> throws
// after
const transport = {
connect({ onMessage }) { ws.addEventListener('message', e => onMessage(JSON.parse(e.data))) },
send(payload) { ws.send(JSON.stringify(payload)) },
} Defensive patterns
Strategy: type-guard
Validate before calling
function isValidTransport(t: ModuleRunnerTransport): boolean {
return typeof t.invoke === 'function' || (typeof t.send === 'function' && typeof t.connect === 'function')
} Type guard
function hasInvokeOrSendConnect(t: ModuleRunnerTransport): boolean {
return typeof t.invoke === 'function'
|| (typeof t.send === 'function' && typeof t.connect === 'function')
} Prevention
- Start from createWebSocketModuleRunnerTransport and modify rather than building a transport from scratch.
- Always implement both connect and send together, or implement invoke.
When it happens
Trigger: Constructing a ModuleRunnerTransport with only send (no connect), only connect (no send), or neither. The check is at moduleRunnerTransport.ts:67 inside createInvokeableTransport, after confirming transport.invoke is absent.
Common situations: Writing a custom transport for the SSR module runner and forgetting connect. Partially copying createWebSocketModuleRunnerTransport and dropping a method. Async transport setup where one method is assigned later but the object is passed before that.
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`…
- invoke was called before connect
- [module runner] Failed to load
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/2ef4575264711adc.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/shared/moduleRunnerTransport.ts:68
const result = await transport.invoke!({
type: 'custom',
event: 'vite:invoke',
data: {
id: 'send',
name,
data,
} satisfies InvokeSendData,
} satisfies CustomPayload)
if ('error' in result) {
throw reviveInvokeError(result.error)
}
return result.result
},
}
}
if (!transport.send || !transport.connect) {
throw new Error(
'transport must implement send and connect when invoke is not implemented',
)
}
const rpcPromises = new Map<
string,
{
resolve: (data: any) => void
reject: (data: any) => void
name: string
timeoutId?: ReturnType<typeof setTimeout>
}
>()
return {
...transport,
connect({ onMessage, onDisconnection }) {
return transport.connect!({View on GitHub (pinned to b4d66fee14)