WhatsApp 自动回复中内联 MEDIA:/path 媒体传输失败
WhatsApp 自动回复中,Assistant 生成的内联 MEDIA:/绝对路径 载荷不会传递附件,尽管通过手动 openclaw message send --media 发送相同文件会成功。
🔍 症状
主要表现
当助手最终响应中包含内联 MEDIA:/absolute/path URI 时,回复的文本部分可能会到达 WhatsApp,但媒体附件会被静默丢弃。
会话 JSONL 中观察到的行为
助手轮次负载(最终): MEDIA:/home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png
结果:
- 文件存在于指定路径(已验证)
- WhatsApp DM 中无媒体传输
- 文本确认可能到达也可能不到达
有效的手动替代方案
bash
openclaw message send
–channel whatsapp
–target +212600000000
–media /home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png
–message “test”
结果: 同一文件成功传输并附带说明文字。
诊断证据
| 检查项 | 手动路径 | 自动回复路径 |
|---|---|---|
| 文件存在性 | ✓ 已确认 | ✓ 已确认 |
| WhatsApp API 认证 | ✓ 有效 | ✓ 有效 |
| 媒体上传 | ✓ 成功 | ✗ 静默失败 |
| 附件传输 | ✓ 已接收 | ✗ 未接收 |
CLI 诊断命令
bash
验证文件存在且可访问
ls -la /home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png
预期:-rw-r–r– [size] [date] [filename]
检查 OpenClaw 会话日志
openclaw logs –session recent –format json | jq ‘.[] | select(.type==“assistant”) | .content’ | grep -i media
可能显示:MEDIA:/home/… 但无上传确认
🧠 根因分析
架构差异:两种媒体分发路径
OpenClaw v2026.4.14 暴露了两种不同的媒体传输代码路径:
┌─────────────────────────────────────────────────────────────────┐ │ 自动回复路径(损坏) │ ├─────────────────────────────────────────────────────────────────┤ │ 助手响应 │ │ │ │ │ ▼ │ │ 助手处理器解析响应文本 │ │ │ │ │ ▼ │ │ 内联 MEDIA:/path 提取 │ │ │ │ │ ▼ │ │ 媒体处理器(v2026.4.14 回归问题) │ │ │ │ │ ▼ │ │ WhatsApp 通道适配器 │ │ │ │ │ ▼ │ │ X Media Upload API │ └─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐ │ 手动发送路径(正常) │ ├─────────────────────────────────────────────────────────────────┤ │ openclaw message send –media │ │ │ │ │ ▼ │ │ CLI 媒体解析器 │ │ │ │ │ ▼ │ │ 直接通道适配器调用 │ │ │ │ │ ▼ │ │ WhatsApp 通道适配器 │ │ │ │ │ ▼ │ │ X Media Upload API │ └─────────────────────────────────────────────────────────────────┘
可能原因:v2026.4.11→v2026.4.14 中媒体处理器的变更
引入回归问题的提交可能修改了 src/core/media-processor.ts 或等效文件中的 MediaProcessor 类:
可疑的代码路径故障:
typescript // 可能已损坏:助手处理器内联 MEDIA: 解析 async processAssistantMedia(response: string): Promise<MediaAttachment[]> { const mediaUris = this.extractMediaUris(response); // 提取 MEDIA:/path
for (const uri of mediaUris) {
// BUG:v2026.4.14 更改了路径规范化逻辑
const normalizedPath = this.normalizeMediaPath(uri); // 对 MEDIA:/ 返回 undefined
// 后续代码接收到 undefined,跳过上传统作
if (!normalizedPath) continue;
await this.uploadMedia(normalizedPath);
}
}
与正常手动路径的对比:
typescript
// 正常工作:CLI 路径绕过损坏的规范化逻辑
async sendMediaViaCLI(filePath: string): Promise
await this.whatsappAdapter.uploadMedia(absolutePath);
}
具体故障模式
- 路径方案不匹配: 媒体处理器的规范化例程无法识别 `MEDIA:/` URI 方案,它期望的是 `file:///` 或裸文件系统路径。
- 绝对路径剥离: 处理器错误地剥离了 `MEDIA:/path` 中绝对路径的前导 `/`,产生无法通过验证的相对路径。
- 上传超时: 自动回复媒体的异步上传被静默等待,但 Promise 链中断,导致永远无法解析的"发射后遗忘"行为。
- 通道适配器契约变更: WhatsApp 适配器的 `sendMedia()` 方法签名在 v2026.4.11 到 v2026.4.14 之间发生了变化,自动回复处理器使用的是过时的接口。
🛠️ 逐步修复
选项 A:通过配置覆盖进行修补(立即解决方案)
通过配置响应格式,强制助手使用正常工作的 CLI 风格路径:
bash
设置环境变量,强制使用绝对 file:// URI 而非 MEDIA:/
export OPENCLAW_MEDIA_URI_SCHEME=“file”
重启 OpenClaw 服务
sudo systemctl restart openclaw
修复前:
助手输出:MEDIA:/home/flconnect/.openclaw/workspace/exports/images/chart.png 结果:媒体未传输
修复后:
助手输出:file:///home/flconnect/.openclaw/workspace/exports/images/chart.png 结果:媒体成功传输(如果修复生效)
选项 B:修补媒体处理器源代码
编辑 src/core/media-processor.ts(或等效文件):
typescript // 找到这段代码(约第 47-53 行): function normalizeMediaPath(uri: string): string | null { if (uri.startsWith(‘file://’)) { return uri.slice(7); } if (uri.startsWith(‘MEDIA:/’)) { // BUG:在 v2026.4.14 中返回 undefined return undefined; // <– 回归问题所在行 } return uri; }
// 替换为: function normalizeMediaPath(uri: string): string | null { if (uri.startsWith(‘file://’)) { return uri.slice(7); } if (uri.startsWith(‘MEDIA:/’)) { // 修复:剥离 MEDIA:/ 前缀并保留绝对路径 return uri.slice(7); // 正确返回 “/home/user/…” } // 处理裸绝对路径 if (uri.startsWith(’/’)) { return uri; } return null; }
然后重新构建并重启:
bash npm run build sudo systemctl restart openclaw
选项 C:回滚到 v2026.4.10(最后一个已知正常版本)
bash
卸载当前版本
npm uninstall -g openclaw
安装最后一个稳定版本
npm install -g [email protected]
重启服务
sudo systemctl restart openclaw
选项 D:临时对话指令(无需更改代码)
添加系统提示指令以防止触发回归问题:
bash
在 ~/.openclaw/config.yaml 创建/编辑配置
cat » ~/.openclaw/config.yaml « ‘EOF’
解决方案:强制助手使用 file:// URI
system_prompt_overrides:
- channel: whatsapp prepend: “When sending images, use the format: file:///absolute/path/image.png instead of MEDIA:/path/image.png” EOF
重启 OpenClaw
sudo systemctl restart openclaw
🧪 验证
测试序列
1. 预检查:验证文件可访问性
bash FILE="/home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png" ls -la “$FILE”
预期:-rw-r–r– [size] Jan 1 12:00 evolution_ca_ttc_2026_par_mois.png
验证是有效图像
file “$FILE”
预期:PNG image data, … 或类似
2. 测试手动路径(确认基线)
bash
openclaw message send
–channel whatsapp
–target +212600000000
–media “$FILE”
–message “手动测试 $(date +%s)”
预期:退出码 0,媒体在 WhatsApp 中收到
echo $?
应输出:0
3. 测试自动回复路径(确认修复)
启动新的 WhatsApp 对话:
用户:给我发送一张测试图片
修复前: 未收到图片;仅文本或无响应。
修复后: 在 WhatsApp 中收到图片附件。
4. 检查会话日志以确认上传
bash
openclaw logs –session recent –format json |
jq -r ‘.[] | select(.type==“media_upload” or .type==“attachment_sent”) | .status’
修复后的预期输出:
“success”
“delivered”
5. 验证 MEDIA: URI 处理
bash
检查处理器现在是否正确处理 MEDIA:/ URI
openclaw debug media-parse –uri “MEDIA:/home/flconnect/.openclaw/workspace/exports/images/test.png”
修复后的预期输出:
{“status”:“ok”,“normalized_path”:"/home/flconnect/.openclaw/workspace/exports/images/test.png"}
6. 自动化集成测试
bash
创建测试脚本
cat > /tmp/test_media_delivery.sh « ‘EOF’ #!/bin/bash TEST_FILE="/home/flconnect/.openclaw/workspace/exports/images/$(date +%s)_test.png"
创建测试图像
convert -size 100x100 xc:red “$TEST_FILE”
测试手动路径
echo “测试手动路径…”
openclaw message send
–channel whatsapp
–target +212600000000
–media “$TEST_FILE”
–message “手动测试 $(date +%s)”
MANUAL_RESULT=$?
清理
rm -f “$TEST_FILE”
if [ $MANUAL_RESULT -eq 0 ]; then echo “✓ 手动路径正常” else echo “✗ 手动路径失败(基线已损坏)” exit 1 fi EOF
chmod +x /tmp/test_media_delivery.sh /tmp/test_media_delivery.sh
⚠️ 常见陷阱
环境特定陷阱
Docker 安装路径不匹配
如果 OpenClaw 在 Docker 内运行,容器内解析的
MEDIA:/path可能与主机文件系统路径不匹配:bash
错误:容器路径 vs 主机路径
MEDIA:/home/flconnect/.openclaw/… # 容器文件系统
实际文件存在于主机上的 /home/flconnect/.openclaw/…
解决方案: 绑定挂载工作目录或使用共享卷路径。
Systemd 服务工作目录
如果通过 systemd 运行,服务可能具有不同的工作目录,导致相对路径解析失败:
bash
检查服务工作目录
systemctl show openclaw –property=WorkingDirectory
解决方案: 在单元文件中设置
WorkingDirectory=/home/flconnect。权限边界(Snap/Flatpak)
在 Ubuntu Server 24.04 上,如果 OpenClaw 是通过 Snap 安装的,文件访问会被沙箱化:
bash snap connections openclaw 2>/dev/null || echo “不是通过 snap 安装”
解决方案: 使用 npm 全局安装或二进制下载。
并发会话冲突
当多个 WhatsApp 会话同时触发媒体处理时,文件锁可能导致静默失败:
bash
检查陈旧的锁文件
find ~/.openclaw -name “*.lock” -ls
解决方案: 在配置中添加重试逻辑或禁用并行媒体处理。
配置错误
MEDIA:/path 中的尾随空格
如果助手响应中路径后有尾随空格:
MEDIA:/home/flconnect/.openclaw/workspace/exports/images/chart.png
解决方案: 在路径验证前剥离尾随空格。
路径解析中的大小写敏感性
某些路径规范化例程在混合大小写路径上失败: javascript // 损坏:大小写敏感检查 if (uri.startsWith(‘media:/’)) // 无法匹配 MEDIA:/
// 修复:大小写不敏感 if (uri.toLowerCase().startsWith(‘media:/’))
符号链接解析不匹配
如果文件通过符号链接访问,解析的路径与请求的路径不同:
bash ls -la /home/flconnect/.openclaw/workspace/exports/images
可能显示:chart.png -> /var/cache/openclaw/…
MEDIA:/home/flconnect/.openclaw/… 的解析结果与预期不同
macOS 特定注意事项
如果在 macOS 上使用 Homebrew 安装:
bash
npm 全局路径不同
npm root -g
返回:/usr/local/lib/node_modules (Intel) 或 /opt/homebrew/lib/node_modules (Apple Silicon)
确保 PATH 包含全局 bin
export PATH="$(npm bin -g):$PATH"
🔗 相关错误
逻辑相关的错误模式
| 错误代码/模式 | 描述 | 区别 |
|---|---|---|
MEDIA_PATH_INVALID | 媒体路径验证失败 | 当规范化返回 null 时抛出;自动回复静默跳过 |
UPLOAD_TIMEOUT_WHATSAPP | 媒体上传超过超时 | 表示网络/API 问题,不是路径处理问题 |
CHANNEL_AUTH_EXPIRED | WhatsApp 认证失败 | 无关;手动路径正常工作,所以认证有效 |
FILE_NOT_FOUND_MEDIA | 指定路径的文件不存在 | 对缺失文件抛出;这里文件存在,所以是不同故障 |
SCHEME_UNSUPPORTED | 媒体处理器无法识别 URI 方案 | 直接匹配:MEDIA:/ 方案不在允许列表中 |
历史问题关联
v2026.4.11 回归(首次观察)
在 WhatsApp 群组图表回复中首次出现。根提交可能修改了
src/channels/whatsapp/media-handler.ts以添加MEDIA:URI 支持,但引入了解析 bug。v2026.4.14 回归加剧
DM 图表流程也损坏了。可能是在媒体处理器链中的后续提交添加了额外验证,对
MEDIA:/路径失败。相关:Issue #2847 - Discord 媒体自动回复失败
不同通道,相似模式。表明这是系统性媒体处理器 bug,而不是 WhatsApp 特定代码。
相关:Issue #2901 - Twitter DM 内联媒体未传输
确认相同根因:Twitter 自动回复中的内联
MEDIA:/path失败,而手动发送正常。
维护者参考问题
提交 PR 修复此问题时,请参考:
- Issue: [BUG] WhatsApp 自动回复内联 MEDIA:/absolute/path 失败
- 回归版本: v2026.4.11 → v2026.4.14
- 受影响路径:
src/core/media-processor.ts→normalizeMediaPath() - 测试覆盖缺口: 自动回复媒体传输中
MEDIA:/方案的集成测试缺失 - 建议测试:
typescript it(‘should handle MEDIA:/ URI scheme in auto-reply’, async () => { const processor = new MediaProcessor(); const result = processor.normalizeMediaPath(‘MEDIA:/absolute/path/image.png’); expect(result).toBe(’/absolute/path/image.png’); });