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

  1. Provide invoke on the transport if you handle RPC yourself.
  2. Otherwise provide both connect(handlers) and send(payload) — the pair is required to synthesize invoke.
  3. 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

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


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)