vitejs/vite · error · SendBeforeConnectError

invoke was called before connect

Error message

invoke was called before connect

What it means

Thrown by the normalized transport's invoke() when called before connect() has completed and there is no in-flight connecting promise. invoke() needs the transport to be connected so the RPC request/response round-trip can complete; invoking earlier rejects immediately.

Solutions

  1. Await transport.connect() before any invoke call.
  2. Let the ModuleRunner own connection lifecycle — avoid calling transport.invoke manually outside the runner.
  3. Catch SendBeforeConnectError (error.name === 'SendBeforeConnectError') and retry once connect resolves.

Example fix

// before
const res = await transport.invoke('fetchModule', [id]) // throws if not connected
// after
await transport.connect()
const res = await transport.invoke('fetchModule', [id])
Defensive patterns

Strategy: validation

Validate before calling

await transport.connect()
await transport.invoke(name, data)

Try / catch

try {
  await transport.invoke(name, data)
} catch (e) {
  if (e?.name === 'SendBeforeConnectError') {
    await transport.connect()
    await transport.invoke(name, data)
  } else throw e
}

Prevention

When it happens

Trigger: Calling transport.invoke(name, data) before awaiting transport.connect(). Throws SendBeforeConnectError at moduleRunnerTransport.ts:250 under the same conditions as the send guard.

Common situations: Custom runner bootstrap that issues an RPC immediately. Calling invoke during construction before the WebSocket/emitter is ready. Forgetting to await an async connect in setup.

Related errors


AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11). Data as JSON: /api/errors/b2c0391291269a7f. Report an issue: GitHub.

Appendix: source

Thrown at packages/vite/src/shared/moduleRunnerTransport.ts:250

      : {}),
    async send(data) {
      if (!invokeableTransport.send) return

      if (!isConnected) {
        if (connectingPromise) {
          await connectingPromise
        } else {
          throw new SendBeforeConnectError('send was called before connect')
        }
      }
      await invokeableTransport.send(data)
    },
    async invoke(name, data) {
      if (!isConnected) {
        if (connectingPromise) {
          await connectingPromise
        } else {
          throw new SendBeforeConnectError('invoke was called before connect')
        }
      }
      return invokeableTransport.invoke(name, data)
    },
  }
}

export class SendBeforeConnectError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'SendBeforeConnectError'
  }
}

export const createWebSocketModuleRunnerTransport = (options: {
  // eslint-disable-next-line n/no-unsupported-features/node-builtins
  createConnection: () => WebSocket
  pingInterval?: number

View on GitHub (pinned to b4d66fee14)