moeru-ai/airi · error

WebSocket server connection failed

Error message

WebSocket server connection failed

What it means

The channel server store's WebSocket client (server SDK Client) reached its terminal 'failed' state: authentication failed terminally, the reconnect retry budget was exhausted, or autoReconnect is disabled. connected is set to false and the initializing lock is cleared so a fresh initialize() can build a new client. This is stronger than onClose (runtime disconnect, SDK keeps auto-reconnecting) - after 'failed', nothing retries on its own.

Source

Thrown at packages/stage-ui/src/stores/mods/api/channel-server.ts:190

          connected.value = false

          if (!hasEverConnected.value) {
            // First handshake failed: clear lock so initialize() can be retried externally.
            initializing.value = null
          }
          // Runtime disconnect: keep initialize/listeners for SDK auto-reconnect.
          // Terminal failure: handled by onStateChange status === 'failed'.
        },
        onStateChange: ({ status }) => {
          if (attempt !== connectionAttempt)
            return

          if (status === 'failed') {
            // SDK entered terminal state (auth terminal / retries exhausted / autoReconnect disabled).
            connected.value = false
            initializing.value = null
            console.warn('WebSocket server connection failed')
          }
        },
        onReady: () => {
          if (attempt !== connectionAttempt)
            return

          const isReconnect = hasEverConnected.value

          hasEverConnected.value = true
          connected.value = true
          flush()
          initializeListeners()

          if (isReconnect) {
            for (const callback of reconnectedCallbacks) {
              try {
                callback()
              }

View on GitHub (pinned to 677329427f)

Solutions

  1. Verify the WebSocket server URL setting and reachability (connect manually with a ws client to the same URL)
  2. Re-authenticate to obtain a fresh token, then call initialize() again - the cleared lock exists exactly to allow this
  3. Check server logs for repeated auth failures or handshake rejections from this client
  4. If retries were exhausted by a transient outage, simply call initialize() once the server is back
  5. Confirm autoReconnect is enabled in the client options if automatic recovery is expected

Example fix

// before: one-shot init, no retry after terminal failure
await channelServer.initialize()

// after: re-arm with backoff when the SDK gives up
watch(connected, (isConnected, wasConnected) => {
  if (wasConnected && !isConnected && !initializing.value)
    retryWithBackoff(() => channelServer.initialize())
})
Defensive patterns

Strategy: retry

Validate before calling

if (!websocketUrl.value || !token)
  throw new Error('WebSocket server URL and auth token are required')
await channelServer.initialize()

Try / catch

watch(connected, (isConnected, wasConnected) => {
  if (wasConnected && !isConnected && !initializing.value)
    retryWithBackoff(() => channelServer.initialize())
})

Prevention

When it happens

Trigger: Handshake rejected with 401/403 due to a wrong or expired token; websocketUrl pointing at a dead or wrong endpoint until retries exhaust; autoReconnect disabled in client options; server-side auth marking the session terminal.

Common situations: Expired auth token after long idle; wrong server URL in settings; reverse proxy dropping WebSocket upgrades so every attempt fails; token audience mismatch after server updates.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/f74100b17137a6d9. Report an issue: GitHub.