Fix "url field must be base64 encoded image" DSH LM Studio error

TroubleshootingPublished 2026-08-27Author: DSH Plugin Hub
DeepSeek HarnessDSHLM Studiobase64 encoded imageimage upload errorwebp
DSH 400: 'url' field must be a base64 encoded image? LM Studio only accepts png/jpeg/gif — webp is rejected. Convert to PNG/JPEG and resend.

DSH rejecting a pasted image sent to a local LM Studio with 400 'url' field must be a base64 encoded image. — the base64 data itself is fine; the root cause is a MIME whitelist: strict OpenAI-compatible backends only accept image/png | jpeg | gif data URIs, and webp/bmp/heic are rejected at the protocol layer. Images copied from browsers or web screenshots are mostly webp and trigger this most often; converting the image to PNG/JPEG before sending bypasses it.

What the DSH base64 encoded image 400 looks like

The error is always HTTP 400 "'url' field must be a base64 encoded image.", it fires when an image is pasted into a chat and sent, and only certain formats trigger it. A reporter reproduced it in practice (discussion thread):

  1. Environment: dsh 0.1.1-rc.2, provider llm-pi-ai (api openai-completions, baseURL pointing at LM Studio), model qwen/qwen3.8-27b (input: [text, image]);
  2. Repro path: configure a local LM Studio vision model → paste a webp image into the chat (most common when copied from a browser or web screenshot) → send and it fails;
  3. A PNG image on the same configuration goes through directly — unrelated to the model and to base64 encoding, only to the image format.

Root cause: a MIME whitelist check, not a base64 validity check

The reporter verified against the backend directly: the rejection is a MIME whitelist check, not a base64 validity check. Per-format results (source):

data URI prefixLM Studio result
data:image/png;base64,…accepted (proceeds to engine decoding)
data:image/jpeg;base64,…accepted
data:image/gif;base64,…accepted
data:image/webp;base64,…400 'url' field must be a base64 encoded image.
data:image/bmp;base64,…400 (same)
data:image/heic;base64,…400 (same)

DSH supplies correct base64 bytes; only the MIME type is the problem. The chain: dsh-llm-pi-ai's userContent() pushes { type: "image", data: <base64>, mimeType: <original> } to pi-ai, which serializes it to data:<original>;base64,… — any format outside the whitelist fails on every request.

Troubleshooting: confirm it is a format issue first

Send a PNG on the same configuration — if it goes through, it is a MIME issue; do not touch the model config. Step by step:

  1. Retest with another format: convert the failing image to PNG or JPEG (macOS: sips; otherwise re-save with a screenshot tool), resend in the same session — passing locks it in as a format problem:
bash
sips -s format png input.webp --out output.png
  1. Check the image format: right-click → Properties to see it; webp/bmp/heic are all on LM Studio's rejection list. On the command line, file tells you directly:
bash
file input.webp
  1. Separate upstream bugs: if the failing image came from DSH's native read_image tool, see Fix DSH read_image "cannot get property fs without inject" — a different bug in the same image neighborhood;
  2. Temporary workaround: convert images to PNG/JPEG before sending (local transcoding), or switch to a backend that accepts webp.

Fix direction: transcode into whitelisted formats before sending

The recommended fix transcodes non-image/png|jpeg|gif image content to PNG in the adapter before sending (sharp is already available in the profile dependency tree; sharp(webpBuf).png().toBuffer() verified working). The reporter and the community add details (source):

  1. Do not fall back to sending the original bytes when transcoding fails: once a route is known to reject webp, a converter failure should remain a typed local failure — sending the original turns a useful decoder/resource error back into the misleading remote 400;
  2. Keep the original attachment immutable and derive a rendition: key derived renditions by source digest + target MIME, encoder/version, size limits, animation policy, orientation/color rules, and quality;
  3. Make the animation policy explicit: animated webp/GIF needs an explicit first-frame/all-frame/reject policy — PNG conversion is not semantically neutral;
  4. Have the route declare supported MIME types: unsupported input should fail before egress when conversion is unavailable or disallowed, instead of handing the user a 400 to guess at.

Notes

  1. The error mentions base64 but is actually a MIME issue — retest with a PNG first instead of spending time on model configuration.
  2. Images pasted from browsers or web screenshots trigger this most often (mostly webp); converting to PNG before sending becomes a useful habit.
  3. Converting animated GIF/webp to PNG loses animation; keep the policy in mind when the vision task cares about frames.
  4. When debugging image issues, #4612 lives in the same "image path" neighborhood — reading both together saves time.

Sources: Discussion #4615, #4612

FAQ

Why does DSH report HTTP 400 'url' field must be a base64 encoded image when sending an image?

The base64 data is fine — the problem is a MIME whitelist: strict OpenAI-compatible backends (LM Studio) only accept image/png, jpeg, and gif data URIs; webp/bmp/heic are rejected with 400 at the protocol layer (source).

Why does PNG go through but webp/bmp/heic do not? Is the base64 wrong?

LM Studio validates the data URI against a MIME whitelist, not base64 validity: png/jpeg/gif pass, webp/bmp/heic always get 400. DSH supplies correct base64 bytes; only the MIME type is the problem.

Browser pastes are mostly webp — how do I avoid the base64 encoded image error?

Convert the image to PNG/JPEG before pasting and sending (screenshot tools and browser save-as offer the format), or transcode locally: on macOS sips -s format png input.webp --out output.png, or in Node use sharp's sharp(webpBuf).png().toBuffer() before attaching.

Is this bug DSH's problem or LM Studio's? Is there a permanent fix?

Both: LM Studio's three-format-only acceptance (png/jpeg/gif) is its protocol limitation; DSH's adapter not negotiating and sending the original MIME as-is is the defect. The fix direction is transcoding into the whitelisted formats before sending (sharp is already available in the profile dependency tree) — that solves both at once.

Sources