April 21, 2026 • 版本: 2026.2.26

[飞书频道WebSocket模式client.on方法错误] - Feishu Channel WebSocket Mode: client.on is not a function

飞书频道在启动时崩溃,提示'client.on不是函数',原因是OpenClaw 2026.2.26中WebSocket客户端初始化失败。

🔍 症状

主要错误表现

飞书频道在初始化时立即终止,并抛出 TypeError:

[default] channel exited: client.on is not a function

执行上下文

根据日志序列显示,错误发生在 WebSocket 握手阶段:

{"subsystem":"gateway/channels/feishu","1":"starting feishu[default] (mode: websocket)"}
{"subsystem":"gateway/channels/feishu","1":"feishu[${accountId}]: bot open_id resolved: ${botOpenId ?? "unknown"}"}
{"subsystem":"gateway/channels/feishu","1":"[default] channel exited: client.on is not a function"}
{"subsystem":"gateway/channels/feishu","1":"[default] auto-restart attempt 3/10 in 20s"}

诊断观察

  • 机器人身份解析成功:`open_id` 日志条目确认 API 身份验证(appId/appSecret)正常工作。
  • 出站通信不受影响:通过飞书频道发送消息正常工作。
  • 入站处理中断:飞书用户发送的入站消息无法被处理。
  • 重试循环已启动:频道进入持续的重启循环,采用指数退避策略。

CLI 诊断命令

要手动诊断此问题:

# Check OpenClaw version
openclaw --version
# Expected: OpenClaw v2026.2.26

# Verify Feishu channel configuration
openclaw config get channels.feishu

# View real-time logs (if logging level permits)
openclaw logs --follow --filter feishu

🧠 根因分析

架构故障点

错误 client.on is not a function 源于飞书频道适配器中不正确的 WebSocket 客户端初始化。代码尝试向缺少预期 EventEmitter 兼容 API 的客户端对象附加事件监听器。

故障序列分析

  1. 频道初始化:OpenClaw 在 WebSocket 模式下实例化飞书频道适配器。
  2. 客户端创建:适配器调用 WebSocket 库构造函数。
  3. API 不匹配:代码期望具有 `.on(event, handler)` 方法的标准 WebSocket 对象,但实际上收到的是:
    • 原始 HTTP 客户端响应对象
    • 包装不当的 WebSocket 连接
    • 具有不兼容 API 表面的 WebSocketShim 实例
  4. 事件绑定失败:对 `client.on('message', handler)` 的调用抛出 TypeError: client.on is not a function
  5. 优雅终止:频道捕获错误并以报告的消息退出。

可能的代码路径

有问题的初始化可能遵循以下模式:

// Hypothetical incorrect implementation (simplified)
const WebSocket = require('ws');

class FeishuChannel {
  async connect(config) {
    const wsUrl = await this.obtainWebSocketEndpoint(config);
    
    // BUG: Using WebSocket constructor directly instead of proper connection
    const client = new WebSocket(wsUrl); // Returns WRONG object type
    
    // This fails because 'client' is not an EventEmitter
    client.on('message', (data) => this.handleMessage(data));
    client.on('error', (err) => this.handleError(err));
    
    return client;
  }
}

依赖上下文

ws 库(或等效库)应返回具有以下方法的对象:

  • on(event: string, listener: Function): this
  • once(event: string, listener: Function): this
  • off(event: string, listener: Function): this
  • send(data: string | ArrayBuffer): void

如果返回的对象缺少 .on(),则频道适配器可能在版本之间被修改,或者依赖版本不匹配改变了返回类型。

版本关联

此回归问题出现在 OpenClaw 2026.2.26 中,表明最近可能更改了:

  • 飞书频道适配器代码
  • WebSocket 库依赖版本
  • 影响模块解析的构建/打包过程

🛠️ 逐步修复

方法 1:降级 OpenClaw(立即缓解)

如果需要立即恢复生产稳定性,降级到已知可用的版本:

# Stop OpenClaw service
sudo systemctl stop openclaw  # Linux
# or
launchctl unload ~/Library/LaunchAgents/com.openclaw.plist  # macOS

# Install previous stable version
npm install -g openclaw@2026.2.20

# Restart service
sudo systemctl start openclaw
# or
launchctl load ~/Library/LaunchAgents/com.openclaw.plist

方法 2:切换到 HTTP 长轮询模式(推荐)

WebSocket 模式不稳定;切换到 HTTP 长轮询作为临时解决方案:

{
  "channels": {
    "feishu": {
      "enabled": true,
      "dmPolicy": "pairing",
      "mode": "polling",
      "accounts": {
        "default": {
          "appId": "cli_a90c15147a38dcb3",
          "appSecret": "***",
          "botName": "Claw",
          "pollingIntervalMs": 30000
        }
      }
    }
  }
}

注意:如果配置字段 mode 无法识别,请继续执行方法 3。

方法 3:应用手动补丁(临时修复)

找到并修补飞书频道适配器源文件:

# Locate the Feishu channel adapter
find /usr/local/lib/node_modules/openclaw -name "feishu*.js" 2>/dev/null
# or
find ~/.openclaw -name "feishu*.js" 2>/dev/null

# Common paths:
# /usr/local/lib/node_modules/openclaw/dist/gateway/channels/feishu/index.js
# ~/.openclaw/plugins/feishu/dist/index.js

在 WebSocket 初始化部分应用以下补丁:

// BEFORE (buggy):
const ws = new WebSocket(url);
ws.on('message', handler);

// AFTER (patched):
const WebSocket = require('ws');
const ws = new WebSocket(url);

// Verify the client has the expected API, wrap if necessary
if (typeof ws.on !== 'function') {
  // Fallback: use EventEmitter-style wrapper
  const { EventEmitter } = require('events');
  const client = new EventEmitter();
  
  ws.onmessage = (event) => client.emit('message', event.data);
  ws.onerror = (event) => client.emit('error', event);
  ws.onopen = (event) => client.emit('open', event);
  ws.onclose = (event) => client.emit('close', event);
  
  // Replace ws with wrapped client
  Object.assign(ws, client);
}

方法 4:强制覆盖 WebSocket 库(高级)

如果怀疑是依赖版本冲突,强制加载正确的 WebSocket 实现:

# Check current ws dependency version
cd /usr/local/lib/node_modules/openclaw
npm ls ws

# Install specific compatible version
npm install ws@8.17.0 --save

添加到 OpenClaw 配置(~/.openclaw/config.json):

{
  "feishu": {
    "websocketOptions": {
      "resolveSocket": true,
      "library": "ws"
    }
  }
}

🧪 验证

确认修复成功

应用任何修复方法后,验证飞书频道是否成功连接:

步骤 1:重启 OpenClaw 服务

# Linux
sudo systemctl restart openclaw

# macOS
launchctl unload ~/Library/LaunchAgents/com.openclaw.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.plist

# Or via PM2 (if using process manager)
pm2 restart openclaw

步骤 2:检查频道状态

openclaw status --channel feishu

# Expected output:
# feishu[default]: connected
# feishu[default]: mode: websocket  # or "polling" if using Method 2
# feishu[default]: uptime: 0d 0h 1m

步骤 3:验证 WebSocket 连接(仅 WebSocket 模式)

# Check for active WebSocket connection on port 9000 (default)
lsof -i :9000 | grep openclaw
# or
netstat -tlnp | grep 9000

# Expected: LISTEN or ESTABLISHED state

步骤 4:测试入站消息接收

从飞书用户向机器人发送测试消息:

# Monitor logs for incoming message
openclaw logs --follow --filter "feishu.*incoming"

# Send a message from Feishu app to the bot
# Expected log entry:
# {"subsystem":"gateway/channels/feishu","1":"feishu[default]: incoming message from user ${userId}"}
# {"subsystem":"gateway/channels/feishu","1":"feishu[default]: message processed successfully"}

步骤 5:验证无重启循环

# Check process uptime
pm2 list
# or
ps aux | grep openclaw

# Expected: stable uptime without auto-restart entries in logs

预期的成功日志序列

{"subsystem":"gateway/channels/feishu","1":"starting feishu[default] (mode: websocket)"}
{"subsystem":"gateway/channels/feishu","1":"feishu[${accountId}]: bot open_id resolved: ${botOpenId}"}
{"subsystem":"gateway/channels/feishu","1":"feishu[default]: WebSocket connected"}
{"subsystem":"gateway/channels/feishu","1":"feishu[default]: channel ready"}

退出码验证

# Check that the process is stable (no rapid exit)
echo $?
# Expected: 0 (process running)
# If channel is working, no 'exited' messages should appear

⚠️ 常见陷阱

  • 配置缓存:OpenClaw 可能会缓存频道配置。更改配置后务必重启服务,如果问题仍然存在,请删除 `~/.openclaw/cache/`。
  • 轮询模式无法识别:`mode: "polling"` 配置字段可能不存在于 v2026.2.26 中。在假设其可用之前,请使用 openclaw config schema channels.feishu 检查频道 schema。
  • WebSocket 库版本冲突:如果 OpenClaw 与项目本地依赖一起全局安装,npm 可能会解析不同的 `ws` 版本。请在两个上下文中使用 npm ls ws 进行审计。
  • Node.js 版本不兼容:Node v25.6.0 是一个非常新的版本。某些原生 WebSocket 插件可能未为此版本预构建。请考虑使用 Node v22.x LTS 作为临时解决方案。
  • macOS ARM64 构建产物:在 Apple Silicon 上,来自 x86_64 构建的缓存原生模块可能导致静默失败。在任何 WebSocket 库更改后运行 npm rebuild
  • Docker 环境隔离:如果在 Docker 中运行 OpenClaw,请确保 WebSocket 库安装在容器内,而不是从主机挂载。卷挂载可能会用不兼容的构建覆盖 node_modules
  • 飞书 API 速率限制:在重启循环期间,多次重连尝试可能会触发飞书的 API 速率限制,导致次级身份验证失败。限制重启尝试或实施退避策略。
  • 凭证轮换:如果在飞书开放平台上最近轮换了 appSecret,配置中的缓存凭证可能已过期。请在配置文件中重新输入凭证。
  • 频道优先级冲突:如果定义了多个飞书账户,频道可能会首先尝试初始化错误的账户。请在频道级别明确设置 "defaultAccount": "default"

🔗 相关错误

上下文错误参考

  • EADDRINUSE 9000:WebSocket 端口冲突。表示另一个进程正在使用飞书 WebSocket 网关端口。使用 lsof -i :9000 检查。
  • WebSocket connection failed: 401 Unauthorized:飞书应用凭证(appId/appSecret)无效或已过期。在飞书开放平台上验证凭证。
  • Feishu API error: app_access_token invalid:令牌刷新失败。频道无法获取有效访问令牌。检查系统时间同步。
  • channel exited: UnhandledPromiseRejection:频道适配器中的异步初始化失败。如果 Promise 未正确处理,这可能是 client.on 错误的前兆。
  • auto-restart loop detected:OpenClaw 内置的防止快速重启循环的保护机制。在 2026.2.26 中连续 10 次失败尝试后出现。使用 openclaw debug 绕过。
  • Cannot find module 'ws':缺少 WebSocket 依赖。如果 npm install 使用了 --omit=optional 运行,则会发生此错误。使用 npm install 重新安装。
  • ECONNREFUSED:飞书 WebSocket 网关无法访问。检查防火墙规则和公司代理设置。
  • Historical: feishu channel not starting after v2025.x update:之前记录的回归问题,具有不同的错误消息。表明飞书频道 WebSocket 实现存在持续稳定性问题。

依据与来源

本故障排除指南由 FixClaw 智能管线从社区讨论中自动合成。