moeru-ai/airi · error · Error
Client is not connected, current status
Error message
Client is not connected, current status: ${this.status} What it means
server-sdk's AiriClient.send() builds the payload and delegates to transport.send, returning false when the transport cannot deliver (e.g. socket not open) (client.ts:343-352). sendOrThrow() wraps that boolean and throws this error, interpolating the client's current status so you can tell whether the socket is still connecting, disconnecting, or closed. It means the event was never handed to the network.
Solutions
- Await client.connect() (or ensureConnected/ready) before the first sendOrThrow
- Use the boolean send() when a dropped event is acceptable, and queue it for retry on false
- Enable autoReconnect and await the connection again after an onConnectionStateChange to disconnected
Example fix
// before const client = createClient(opts) client.sendOrThrow(event) // throws: status 'connecting' // after const client = createClient(opts) await client.ensureConnected() client.sendOrThrow(event)
Defensive patterns
Strategy: validation
Validate before calling
await client.ensureConnected() // resolves only when the transport is open
if (!client.send(event)) {
// transport refused the frame; queue and retry after reconnect instead of throwing
pendingEvents.push(event)
} Try / catch
try {
client.sendOrThrow(event)
}
catch (error) {
if (error instanceof Error && error.message.startsWith('Client is not connected')) {
await client.ensureConnected()
client.sendOrThrow(event) // retry once after the socket is open
}
else throw error
} Prevention
- Await connect()/ensureConnected() once at startup before any sendOrThrow
- Prefer boolean send() plus an outbound queue for non-critical events
- Subscribe to onConnectionStateChange and pause sends while disconnected
When it happens
Trigger: Calling sendOrThrow before awaiting connect()/ready()/ensureConnected(), sending right after the socket dropped and before auto-reconnect finishes, or sending after close(). The status string in the message tells you which state the transport was in.
Common situations: Fire-and-forget usage that skips the connection promise, app shutdown paths that flush events after close, network blips where autoReconnect is disabled or still in its retry window.
Related errors
- Invalid AIRI websocket message.
- WebSocket server connection failed
- Wrapped extension peer client does not support event…
- [builtIn_mcpListTools] failed to list tools:
- Channel gateway stream error:
AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18).
Data as JSON: /api/errors/87b8062c1fa4ddd5.
Report an issue: GitHub.
Appendix: 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 677329427f)