CherryHQ/cherry-studio · critical · Error

Feishu WebSocket connection failed: ${error instanceof Error

Error message

Feishu WebSocket connection failed: ${error instanceof Error ? error.message : String(error)}

What it means

Thrown when Lark.WSClient.start() rejects during Feishu's WebSocket (long-connection) setup. The adapter wraps the SDK's start() in try/catch, nulls out wsClient on failure so later disconnect logic doesn't touch a half-built client, then re-throws with the underlying error message.

Source

Thrown at src/main/ai/channels/adapters/feishu/FeishuAdapter.ts:433

      'im.message.receive_v1': async (data: unknown) => {
        const event = data as FeishuMessageEvent
        this.handleMessageEvent(event)
      }
    })

    this.wsClient = new Lark.WSClient({
      appId: this.appId,
      appSecret: this.appSecret,
      domain: larkDomain,
      loggerLevel: Lark.LoggerLevel.error
    })

    try {
      await this.wsClient.start({ eventDispatcher })
    } catch (error) {
      // Clean up so performDisconnect doesn't try to use a broken client
      this.wsClient = null
      throw new Error(`Feishu WebSocket connection failed: ${error instanceof Error ? error.message : String(error)}`)
    }

    this.markConnected()
    this.log.info('Feishu bot started (WebSocket)')
  }

  /**
   * Start the Feishu App Registration Device Flow in the background.
   * Emits the QR URL immediately via 'qr' event and IPC, then polls
   * asynchronously.  Does NOT block the caller.
   */
  private startRegistrationInBackground(signal: AbortSignal): void {
    this.log.info('Starting Feishu app registration flow (background)', {
      domain: this.domain
    })

    this.sendQrToRenderer('', 'pending')

View on GitHub (pinned to 726446b54c)

Solutions

  1. Confirm appId/appSecret/domain match an enabled app in the Feishu Developer Console; toggle 'Robot' capability on.
  2. Check the embedded underlying message — 'invalid app_id or app_secret' means credentials; a connection/timeout message means network/firewall.
  3. Ensure the host can reach the WebSocket gateway (openlark/lark domain) — test from the same network.
  4. Pin or upgrade @larksuiteoapi/node-sdk to a version compatible with the adapter's WSClient usage.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight credential/domain check before connect.
function canStartFeishuWs(appId?: string, appSecret?: string, domain?: string): boolean {
  return Boolean(appId && appSecret && (domain === 'feishu' || domain === 'lark'))
}

Type guard

function isFeishuWsConnectError(e: unknown): e is Error {
  return e instanceof Error && e.message.startsWith('Feishu WebSocket connection failed:')
}

Try / catch

try {
  await feishu.connect()
} catch (e) {
  if (isFeishuWsConnectError(e)) {
    logger.error('Feishu connect failed', e)
    notifyUser('Check Feishu appId/appSecret/domain and network')
    return // stay disconnected; do not crash
  }
  throw e
}

Prevention

When it happens

Trigger: this.wsClient.start({ eventDispatcher }) throws — appId/appSecret rejected by Feishu's handshake, wrong domain (feishu vs lark), network/DNS failure reaching the WebSocket gateway, SDK internal error, or a malformed eventDispatcher.

Common situations: App credentials typed for the wrong domain (feishu.cn vs larksuite.com), the app disabled or under review in the Feishu console, corporate firewall blocking the WebSocket endpoint, or an SDK upgrade that changed the start() contract.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/9660b9ebaa08aac0. Report an issue: GitHub.