moeru-ai/airi · error · Error

Client is not connected, current status: ${this.status}

Error message

Client is not connected, current status: ${this.status}

What it means

Thrown by `Client.sendOrThrow()` when the underlying `send()` returns false, meaning the transport reported a non-OK send result (typically because the socket is not open/connected). The message includes the current connection `status` to aid diagnosis. `sendOrThrow` is the throwing variant of `send()`, which otherwise returns a boolean.

Source

Thrown at packages/server-sdk/src/client.ts:356

    }

    this.eventListeners.delete(event)
  }

  send(data: WebSocketEventOptionalSource<C>): boolean {
    const payload = this.createPayload(data)
    const result = this.transport.send(payload)
    if (!result.ok) {
      return false
    }

    this.opts.onAnySend(payload)
    return true
  }

  sendOrThrow(data: WebSocketEventOptionalSource<C>): void {
    if (!this.send(data)) {
      throw new Error(`Client is not connected, current status: ${this.status}`)
    }
  }

  close(code?: number, reason?: string): void {
    this.transport.close(code, reason)
  }

  private createReconnectOptions(): false | ReconnectOptions {
    if (!this.opts.autoReconnect) {
      return false
    }

    return {
      retries: (attempt, error) => {
        const normalized = this.normalizeError(error, 'Failed to connect websocket client')
        if (isTerminalAuthenticationServerErrorMessage(normalized.message)) {
          return false
        }

View on GitHub (pinned to 27111382b4)

Solutions

  1. Wait for the client's connected/open status before sending, or prefer the non-throwing `send()` and check its boolean return.
  2. Enable `autoReconnect` and queue outbound events until reconnection succeeds, rather than sending during a disconnected window.
  3. Inspect the `status` field in the error message to identify the state (connecting/closed/reconnecting) and act accordingly.
  4. Handle terminal auth failures distinctly so you do not keep retrying sends on a dead session.

Example fix

// before
client.sendOrThrow(event)

// after
if (!client.send(event)) {
  queue.push(event) // replay once reconnected
}
Defensive patterns

Strategy: validation

Validate before calling

if (!client.send(event)) {
  // transport reported not-OK; queue and replay, or surface to the user
  outboundQueue.push(event)
}

Type guard

function isClientReady(client: { status: string }): boolean {
  return client.status === 'open' || client.status === 'connected'
}

Try / catch

try {
  client.sendOrThrow(event)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Client is not connected')) {
    outboundQueue.push(event) // replay once reconnected
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling `client.sendOrThrow(event)` while the client is not in a connected state — e.g. before the connection has opened, after it has closed, during reconnection backoff, or after a terminal auth failure. Any transport send that returns `{ ok: false }` triggers it.

Common situations: Sending immediately after constructing the client without waiting for the open/ready event; sending during/after an unexpected disconnect; sending after the server closed the connection (auth failure, idle timeout); calling sendOrThrow in an event handler that fires post-close.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/87b8062c1fa4ddd5. Report an issue: GitHub.