DSH 发图片报 "url field must be a base64 encoded image"?LM Studio 转码排查
DSH 里粘贴图片发给本地 LM Studio 被 400 拒绝、报 'url' field must be a base64 encoded image.——base64 数据本身没问题,根因是 MIME 白名单:严格 OpenAI 兼容后端只接受 image/png | jpeg | gif 的 data URI,webp/bmp/heic 在协议层直接拒绝。 从浏览器/网页截图粘贴出来的图多为 webp,最容易触发;把图片转成 PNG/JPEG 再发即可绕过。
DSH 发图片报 base64 encoded image 400 长什么样
报错固定为 HTTP 400 "'url' field must be a base64 encoded image.",发生在把图片粘贴进聊天发送时,且只有特定格式触发。 报告者实跑复现(讨论原文):
- 环境:dsh
0.1.1-rc.2,Providerllm-pi-ai(apiopenai-completions,baseURL 指向 LM Studio),模型qwen/qwen3.8-27b(input: [text, image]); - 复现路径:配置本地 LM Studio 视觉模型 → 把一张 webp 图粘贴进聊天(浏览器/网页截图复制出来最常见)→ 发送即失败;
- 消息里换用 PNG 图同一配置直接通过——说明与模型、与 base64 编码都无关,只与图片格式有关。
根因:MIME 白名单校验,不是 base64 校验
报告者直接对后端验证:拒绝是 MIME 白名单检查,而不是 base64 合法性检查。 逐格式实测(来源):
| data URI 前缀 | LM Studio 结果 |
|---|---|
data:image/png;base64,… | 接受(进入引擎解码) |
data:image/jpeg;base64,… | 接受 |
data:image/gif;base64,… | 接受 |
data:image/webp;base64,… | 400 'url' field must be a base64 encoded image. |
data:image/bmp;base64,… | 400(同上) |
data:image/heic;base64,… | 400(同上) |
DSH 提供的 base64 字节是正确的,问题只出在 MIME 类型上。链路是:dsh-llm-pi-ai 的 userContent() 把 { type: "image", data: <base64>, mimeType: <原始格式> } 推给 pi-ai,pi-ai 序列化成 data:<原始格式>;base64,…——只要格式不在白名单,每次请求都失败。
排查步骤:先确认是格式问题
换一张 PNG 图同一配置发送——能过就是 MIME 问题,别去折腾模型配置。 按步骤确认:
- 换格式复测:把报错的图转成 PNG 或 JPEG(macOS 用
sips,或截图工具重存),同一会话重发,通过即锁定为格式问题:
sips -s format png input.webp --out output.png
- 核对图片格式:右键图片「属性」看格式,webp/bmp/heic 都在 LM Studio 的拒绝名单内;命令行可用
file直接判断:
file input.webp
- 区分上游 bug:若发的是 DSH 原生
read_image工具读出的图,参见《DSH read_image 图片工具报 cannot get property "fs" without inject》——那是另一个 bug,同属图片路径但根因不同; - 临时绕行:发送前把图片统一转成 PNG/JPEG(本地转码),或改用一个接受 webp 的后端。
修复方向:发送前转码成白名单格式
推荐的修复是在适配层把非 image/png|jpeg|gif 的图片内容转码成 PNG 再发送(sharp 已在 profile 依赖树里可用,sharp(webpBuf).png().toBuffer() 验证可行)。 报告者与社区补充了细节(来源):
- 不要在转码失败时把原始字节发出去:一旦路由已声明拒绝 webp,转码失败应当保留为本地类型化错误;「发送原始图」会把有用的解码/资源错误又变回误导性的远端 400;
- 保留原附件、派生副本:原始 content-addressed 附件保持不可变,派生渲染按「源摘要 + 目标 MIME + 编码器/版本 + 尺寸限制 + 动画策略 + 方向/颜色规则 + 质量」为键生成;
- 动画策略要显式:动画 webp/gif 需要「只取首帧 / 全帧 / 拒绝」的明确策略——PNG 转换不是语义中立的操作;
- 路由声明支持哪些 MIME:让路由声明支持列表,遇到不支持的输入且无法/不允许转码时,在出网前就失败,而不是把 400 甩给用户猜。
注意事项
- 报错指向 base64 但实际是 MIME 问题——先换 PNG 复测,别在模型配置上浪费时间。
- 粘贴来自浏览器/网页截图的图最容易触发(多为 webp);发送前养成转 PNG 的习惯即可绕开。
- 动画 GIF/webp 转 PNG 会丢动画,视觉任务对帧敏感时留意策略。
- 排查图片问题时,#4612 与本文同属「图片路径」一带,两条一起看能省时间。
常见问题
base64 数据本身没问题,问题在 MIME 白名单:严格 OpenAI 兼容后端(LM Studio)只接受 image/png、jpeg、gif 的 data URI,webp/bmp/heic 在协议层直接被 400 拒绝(来源)。
LM Studio 对 data URI 做的是 MIME 白名单校验而不是 base64 合法性校验:png/jpeg/gif 通过,webp/bmp/heic 一律 400。DSH 提供的 base64 字节是对的,问题只出在 MIME 类型。
先把图片转成 PNG/JPEG 再粘贴发送(微信/QQ 截图、浏览器另存为均可选格式);或本地转码:macOS 用 sips -s format png input.webp --out output.png,Node 用 sharp 的 sharp(webpBuf).png().toBuffer() 后再贴。
两边都有份:LM Studio 只收 png/jpeg/gif 三格式是它的协议限制;DSH 适配层不协商、按原始 MIME 原样发送是缺陷所在。修复方向是适配层在发送前把非白名单格式转成 PNG(sharp 已在 profile 依赖树里可用),把图片转码成白名单格式就能同时解决。
来源
- deepseek-harness Discussion #4615:dsh-llm-pi-ai 原样发送非 png/jpeg/gif 图片,LM Studio 以 400 拒绝 webp· deepseek-ai(GitHub Discussions)
- deepseek-harness Discussion #4612:原生 read_image 工具报 cannot get property 'fs' without inject(同属图片路径)· deepseek-ai(GitHub Discussions)