
最近在 Claude Code 里遇到一个让人懵的错:
An image in the conversation exceeds the dimension limit for many-image requests (2000px). Start a new session with fewer images.
我当时贴的是一张完全正常的 100×200 小图。按直觉这应该是"最后那张图超大",但实际不是。这是一个累积性 bug,触发时机、原因、解法都反直觉,一旦踩到还会反复踩。这篇文章把规则、原理、可直接用的工具都讲清楚。
现象
一次典型触发路径:
- 某个 Claude Code 会话里,你聊了半天,中途贴过几张截图(假设有一张是 2500×1800,Retina 截图很容易超过 2000 px)。
- 继续往下聊,又贴了一张新的截图(不管多大)。
- 这次请求 直接失败,报上面那个 dimension limit。
- 之后你纯文字发消息也会失败。会话彻底卡住,除了开新会话没别的选项。
如果你用的是 Paseo(多 tab 聚合 Claude Code / Codex 的客户端),一个 tab 挂掉不影响别的,但那个 tab 里一整段有价值的上下文基本就废了。
原因:Anthropic API 的多图分档规则
Anthropic 的 Messages API 对图片有两档尺寸规则:
| 请求里的图片数 | 单张图最大尺寸 |
|---|---|
| 1 张(单图模式) | 最大 8000×8000 |
| ≥ 2 张(多图模式) | 每张每边必须 ≤ 2000 px |
这里的关键是**“请求里的图片数”**,而不是"你这次消息带的图片数"。Claude Code(以及任何兼容客户端)的工作方式是:每次请求都把整个对话历史——包括历史所有图片——作为 context 重新发送。所以:
- 你第一次贴一张 2500×1800 的图,单图模式,OK。
- 你第二次再贴任何一张图,哪怕是 50×50 的一个 emoji 截图,这次请求里就有 2 张图,多图模式触发。回头检查历史,第一张那 2500 宽的违反 2000 px 规则,整个请求被拒绝。
- 之后你哪怕不贴图,只发文字,历史里那 2 张图仍然在 context 里,请求依然被拒绝。
所以这不是"最后那张图有问题",而是"从第 2 张图开始,历史里任何一张超过 2000 px 都会挂掉整个会话"。
Retina 显示器截图天然容易超标:标准 MacBook 3x 缩放下,一张显示尺寸 800×600 的窗口截图实际像素是 2400×1800——已经过线。
基础解法:剥离 JSONL 里的 base64 图片
Claude Code 把每个会话存成 JSON Lines:~/.claude/projects/<project-slug>/<session-uuid>.jsonl。每一行是一条消息,图片以 base64 形式嵌在消息里,类似:
{
"role": "user",
"content": [
{ "type": "text", "text": "看看这个报错" },
{ "type": "image", "source": { "type": "base64", "data": "iVBORw0...巨长的 base64..." } }
]
}
救援思路很简单:把 source 替换成占位符,base64 不再嵌在 context 里,多图规则不再触发。你的 prompt 文字(“看看这个报错”)和 Claude 当时对图的文字解读(“截图显示了 404 错误…")都原样保留。对话语义延续,你失去的只是"回翻查看图片本身"的能力。
实现这个逻辑的现成工具是 ianbmacdonald/claude-session-rescue。核心是一个纯 Python 脚本,原子写入 + 自动 .bak 备份:
git clone https://github.com/ianbmacdonald/claude-session-rescue ~/tools/claude-session-rescue
# Dry-run 看会改什么
python3 ~/tools/claude-session-rescue/scripts/session_rescue.py \
--session-id abc12345 --dry-run
# 正式执行
python3 ~/tools/claude-session-rescue/scripts/session_rescue.py \
--session-id abc12345
跑完你回 Claude Code 继续发消息就能走通了。
我踩到的两个实际痛点
用上面的基础脚本修掉第一次之后,我又踩到两个新问题:
痛点 1:Paseo 里我不知道 tab 对应哪个 sessionId
我习惯在 Paseo 里给 tab 起有意义的名字(按项目域划分),但救援脚本需要 session ID 前 8 位作为参数。我得先去 ~/.paseo/agents/<project>/*.json 里翻找对应 agent 的 persistence.sessionId——每次都这样挺烦。
解法:写个包装脚本,自动按 tab 名查 sessionId。
痛点 2:问题会复发,需要定时预防
救援本身是"事后补救”——你已经撞到错误才去跑。但随着使用量增加,会话里积累的截图越来越多,第二天可能又挂。最好是每天自动跑一次,而且要有安全阀,不能在我正在聊的时候把 JSONL 抽走。
需要的安全阀:
- 跳过活跃 session:如果某个 session 对应的
claude进程正在跑,跳过——避免写冲突。 - 跳过刚写入的:JSONL 在最近 N 分钟内被改过 → 用户可能正在聊,跳过。
- 图片数阈值:图片少于 N 张的 session 不清——保留近期视觉上下文。
- 备份轮转:每次跑都会多一份
.bak,长期下来会累积。只保留最近 K 份。
工具化
我自己整理了一套脚本:核心引用上游 ianbmacdonald/claude-session-rescue 处理 JSONL 剥图,外面再包一层 Paseo 友好的手动救援 + 定时版 + 4 道安全阀。下面的代码片段你可以直接拿走拼装。
scripts/paseo_rescue.sh — Paseo 友好的手动救援
# 列出所有命名 tab 和图片数
bash paseo_rescue.sh
# 预览
bash paseo_rescue.sh MyTabName --dry-run
# 正式救援
bash paseo_rescue.sh MyTabName
# 批量
bash paseo_rescue.sh --all
脚本解析 ~/.paseo/agents/<project>/*.json 里的 title 字段和 persistence.sessionId,自动映射。使用前改脚本顶部的 PASEO_AGENTS_DIR 变量指到你的项目 slug 就行。
scripts/paseo_rescue_auto.sh — 每日定时版 + 4 道安全阀
核心代码片段:
while IFS='|' read -r name sid cwd; do
jsonl="$CLAUDE_PROJECTS/${cwd_enc}/${sid}.jsonl"
# Valve 1: 活跃 claude 进程
if pgrep -f "claude.*${sid:0:8}" >/dev/null; then
log "[$name] skip: active process"
continue
fi
# Valve 2: 最近 30 分钟内修改过
mtime=$(stat -f%m "$jsonl")
if [ $(($(date +%s) - mtime)) -lt 1800 ]; then
log "[$name] skip: recent write"
continue
fi
# Valve 3: 图片数阈值
img_count=$(grep -o '"type":"image"' "$jsonl" | wc -l)
if [ "$img_count" -lt 5 ]; then
log "[$name] skip: only $img_count images"
continue
fi
# 清理 + 记录
python3 "$RESCUE_SCRIPT" --session-id "${sid:0:8}"
# Valve 4: .bak 轮转
ls -1t "${sid}.jsonl.bak"* | tail -n +4 | xargs rm -f
done < <(list_agents)
配合 macOS LaunchAgent / Linux systemd timer(examples 目录里有现成模板),每天本地时间 18:30 跑一次。有清理动作时 Telegram 推送摘要,空跑不通知。
监控纳管
我本地的监控系统(另一个话题)会把这个定时任务纳入统一的"备份任务"页面:
- 任务状态(绿/黄/红)
- 上次成功时间、下次运行时间
- 清理的 session 数、释放的空间、处理的图片数
- 失败自动 Telegram 告警
这是用我自己的监控框架集成的,repo 里没包含(避免绑定特定架构),但你可以参考 paseo_rescue_auto.sh 的日志格式自己接入你的监控。
实用建议(预防 > 救援)
最好的救援是根本不需要救援:
- 贴截图前先缩到 ≤ 1920 px 宽。macOS 可以
sips -Z 1920 file.png,或用 Shottr / CleanShot 等默认 1x 输出的第三方工具。 - 长会话里节制贴图,能用文字描述就别贴图。
- 对高强度用户(每天贴 10+ 张截图),开个每日定时清理,设
--min-images 5左右。 - 对运维/研究场景,记得把重要结论让 Claude 文字化总结后再清理——图没了但文字记忆还在。
关于 API 规则的题外话
Anthropic 这个多图规则我没在官方文档的显眼位置见过,实际踩到才反推出来。这种"规则触发后回溯检查历史"的设计对客户端不太友好——用户感知是"我明明只贴了一张小图怎么就挂了"。如果 Claude Code 能在 API 返回这个错误时自动提示"是第 N 条消息里那张图超限",体验会好很多。
不过既然规则摆在那,我们能做的就是把救援链路做顺滑。这套工具对我来说让这个 bug 从"每次都要手忙脚乱"变成"18:30 自动处理,我一般都感知不到"。
链接
- 上游核心:https://github.com/ianbmacdonald/claude-session-rescue(JSONL 剥图算法,本文 wrapper 全部依赖它)
如果对你有用,在 X @panshi8848 反馈使用中遇到的问题。
📷 封面图 · Flux Schnell AI 生成 · panshi.io 品牌风格