OpenClaw 踩坑记:Cron 任务 Feishu 推送失败

原始问题: 我的agent x 中 没有配置通知渠道,只配置了定时任务,并指定了 feishu 渠道中的以前用过的1个会话。一开始好用过一阵子,但最近几天 一直无法推送到这个渠道中。为什么呢?

1. 配置概况

  • Agent : x(无任何 notifyChannel / channel bindings)

  • Cron job : 科技热点监控(ID: e4f5f448-...

  • 关键配置 :

    json 复制代码
    "sessionTarget": "isolated",
    "delivery": {
      "mode": "announce",
      "channel": "feishu",
      "to": "ou_bfeb607c232d23cf041e0b989f33xxxx",
      "bestEffort": true
    }

2. 问题:Feishu API 400 错误,不是 session 路由问题

从运行日志(cron/runs/e4f5f448-...jsonl)可以看到,agent 自己在 summary 里已经报告了问题:

"飞书消息发送(ou_bfeb607c232d23cf041e0b989f33xxxx)返回 400 错误,疑似 target ID 或权限配置变动" "Feishu API 连续报错(400),本轮无法推送"

deliveryStatus: "not-delivered", deliveryError: "⚠️ ✉️ Message failed" --- 执行成功,只是投递失败


3. 为什么 Feishu DM 会报 400?

核心原因:delivery.accountId 未指定,导致系统选错了 Feishu 应用账号。

Feishu ou_ open_id 是应用私有的:

在飞书中,ou_xxx每个用户在某个特定 App 下的 open_id ,不同 App 对同一用户生成不同的 ou_。配置里有 5 个飞书 App 账号:

账号名 App ID 说明
coder7 cli_a9f0... 仅限特定群组 allowlist
developer cli_a977... ---
manager cli_a9a3... ---
newsreporter cli_a874... ---
writer cli_a926... ---

ou_bfeb607c232d23cf041e0b989f33xxxx 是从某一个特定 App 获取的该用户 open_id。当系统选错了 App 来发送时,这个 open_id 对该 App 无效 → Feishu API 返回 400。


4. 代码路径分析(为什么会选错账号)

4.1 投递目标解析链

delivery-target.ts 中的 resolveDeliveryTarget

javascript 复制代码
channel = "feishu", to = "ou_...", accountId = undefined(未设置)

→ 尝试从 session store 推断: 
    job.sessionKey = null → 找 mainSessionKey
    → sessions.json 里 lastChannel=feishu 的 entry: 0个!
    → accountId 仍为 undefined

→ 尝试从 channel bindings 推断:
    buildChannelAccountBindings(cfg) → agent x 无 feishu 绑定
    → accountId 仍为 undefined

→ resolveOutboundTargetWithRuntime({ channel:"feishu", to:"ou_...", accountId:undefined })
    → Feishu plugin 拿到 undefined accountId,自动选一个 App
    → 选中的 App 不是 ou_xxx 对应的那个 App
    → API 返回 400

4.2 为什么一开始能用

当初能推送,说明当时 sessions.json 中存在 Feishu 会话记录,lastAccountId 有值(那个用于对话的 App),系统能正确推断用哪个账号。

后来session reset/清理 导致 lastChannel/lastAccountId 被清空:

  • resolveCronSession(session.ts)使用「direct」类型的 session reset 策略
  • 默认策略:每日 4 点 resetDEFAULT_RESET_MODE = "daily", DEFAULT_RESET_AT_HOUR = 4
  • reset 后新 session 强制清零:lastChannel: undefined, lastTo: undefined, lastAccountId: undefined
  • 写回磁盘后,路由信息永久丢失

五、修复方法

在 cron job 里明确指定 accountId,即发送时用哪个飞书 App:

bash 复制代码
# 先确认 ou_bfeb607c232d23cf041e0b989f33xxxx 是哪个 App 的 open_id
# 查看 agent x 最近的飞书会话是通过哪个账号进来的
openclaw cron edit e4f5f448-550a-480b-a9de-751a0930573e --account newsreporter   # 或 developer / manager,根据实际情况选

或者直接编辑 ~/.openclaw/cron/jobs.json

json 复制代码
"delivery": {
  "mode": "announce",
  "channel": "feishu",
  "to": "ou_bfeb607c232d23cf041e0b989f33xxxx",
  "accountId": "newsreporter",   ← 加上这行
  "bestEffort": true
}

或者在Control UI上编辑,在 高级-〉Account ID 中填写正确的 feishu account id:

如何确认正确的 accountId?

你在创建飞书渠道时,输入过 appIdappSecretOpenClaw 的配置文件 ~/.openclaw/openclaw.json 中有你的所有渠道的配置,找到你要推送的那个账号。或者在终端执行命令:

bash 复制代码
openclaw config get channels.feishu.accounts

输出类似下方:

bash 复制代码
{
  "coder7": {
    "appId": "cli_a9f07d778638xxxx",
    "appSecret": "__OPENCLAW_REDACTED__",
    "domain": "feishu",
    "enabled": true,
    "connectionMode": "websocket",
    "groupPolicy": "allowlist",
    "groupAllowFrom": [
      "oc_aa231052038c2e7f0e1d95e7f9e4f00e"
    ]
  },
  "enable": true,
  "developer": {
    "appId": "cli_a9f774acb9b9xxxx",
    "appSecret": "__OPENCLAW_REDACTED__",
    "domain": "feishu",
    "enabled": true
  },
  "manager": {
    "appId": "cli_a9a3bef1b4f8xxxx",
    "appSecret": "__OPENCLAW_REDACTED__",
    "domain": "feishu",
    "enabled": true
  },
  "newsreporter": {
    "appId": "cli_a8748b16b279xxxx",
    "appSecret": "__OPENCLAW_REDACTED__",
    "domain": "feishu",
    "enabled": true
  },
  "writer": {
    "appId": "cli_a926ff9fff78xxxx",
    "appSecret": "__OPENCLAW_REDACTED__",
    "domain": "feishu",
    "enabled": true
  }
}

在你选定的那个飞书账号里(我这里是newsreporter)发送 /whoami,系统会给你推当前的open_id

要确保 Account IDopen_id 是对应的即可。


六、附:Feishu ou_ ID 的机制(避免再踩坑)

概念 格式 特性
open_id ou_xxx App 私有:同一用户在不同 App 下的 open_id 不同
union_id on_xxx ISV 账号内跨 App 一致
user_id 企业内固定 全局唯一,需 ISV 权限
chat_id oc_xxx 群聊 ID,与 App 无关

结论 :配置 delivery.to = "ou_xxx" 时,必须同时配 delivery.accountId 来锁定是哪个 App 发出的,否则系统随机选一个 App,很可能用错 App 导致 400。


七、总结

现象 :近期飞书渠道推送消息时总失败(以前好用), Feishu API 持续返回 400 错误

根本原因delivery 配置中没有指定 accountId。你有 5 个飞书 Bot App(coder7/developer/manager/newsreporter/writer),ou_bfeb607c232d23cf041e0b989f33xxxx 这个 open_id 只对某一个特定 App 有效。

为什么一开始好用 :session store 里保存了 lastAccountId(记录了和这个用户对话用的是哪个 App),系统路由时能正确找到。

为什么后来失效 :session 每日 4 点 reset(默认策略),清掉了 lastAccountId,之后系统选了一个错误的 App 去发 DM → 400。

修复 :在 cron job 的 delivery 里加 accountId,指定正确的飞书 App 账号(先通过日志确认原来是哪个账号在和 ou_bfeb607c... 对话的)。

相关推荐
修己xj7 小时前
差生文具多?我给自己改造了一款AI周计划工具
github
葫芦和十三8 小时前
图解 MongoDB 28|块与迁移:balancer 怎么均衡数据
后端
葫芦和十三8 小时前
图解 MongoDB 27|分片策略:范围分片 vs 哈希分片
后端·mongodb·agent
paopaokaka_luck8 小时前
英语单词学习系统的设计与实现(基于艾宾浩斯遗忘曲线的智能复习机制、语音朗读、多题型测试与错题自动收录、Echarts图形化分析)
vue.js·spring boot·后端·echarts
我叫黑大帅9 小时前
MySQL 并发插入竞态问题:原子写入实践指南
后端·mysql·面试
zhangxingchao10 小时前
AI大模型核心八:从 Agent Skill、长文档 RAG 到知识库更新与训练策略
前端·人工智能·后端
我叫黑大帅10 小时前
别再手动写 updated_at了,这坑我踩过
后端·面试·go
zhangxingchao10 小时前
AI大模型核心七:从 Workflow、RAG、记忆治理到幂等性
前端·人工智能·后端
阿里嘎多学长11 小时前
2026-07-07 GitHub 热点项目精选
开发语言·程序员·github·代码托管
犀利豆12 小时前
AI in Harness(二)
java·人工智能·后端