Summary
The image tool fails with the opaque error Failed to optimize image on every image in environments where the optional sharp package is not installed. The vision pipeline has no fallback and no clear indication that a missing native dependency is the cause.
Environment
- OpenClaw: 2026.4.25 (aa36ee6)
- Node: v22.22.2
- OS: Ubuntu 24.04.4 LTS (x86_64)
- Install: Linux VPS, OpenClaw installed globally to
/usr/lib/node_modules/openclaw/
Reproduction
- Install OpenClaw on a fresh Linux host where
sharp is not in node_modules (it is listed in OpenClaw's package.json onlyBuiltDependencies array but is not in dependencies / optionalDependencies, so it can be skipped during global install).
- Send any image to the agent (Discord attachment, file path, etc.).
- Call the
image tool against the saved path:
image({ image: "/path/to/any.jpg", prompt: "..." })
- Observe the response:
{ "status": "error", "tool": "image", "error": "Failed to optimize image" }
This happens regardless of input format (JPEG, PNG, WebP), size, dimensions, or EXIF orientation.
Root cause
/usr/lib/node_modules/openclaw/dist/extensions/media-understanding-core/image-ops.js does a dynamic import("sharp") at runtime. When the package isn't installed, every call to resizeToJpeg throws.
/usr/lib/node_modules/openclaw/dist/web-media-DaFqOHhS.js's optimizeImageToJpeg function tries 25 size×quality combinations (5 sides × 5 qualities) and swallows every per-attempt exception with try {} catch {}. After all 25 fail, it throws the generic Failed to optimize image — losing the underlying "sharp not found" cause entirely.
So the user-facing failure is one opaque message regardless of:
- Sharp being missing (this case)
- An actual image-corruption issue
- An actual size/quality budget that nothing fits in
Suggested fix
Either or both:
1. Make sharp a hard dependency. It's clearly required for image attachment processing on non-macOS hosts (the only fallback is sips, which is macOS-only). Listing it in onlyBuiltDependencies without listing it in dependencies is what allows it to be skipped on Linux installs.
2. Surface the underlying error. In optimizeImageToJpeg, capture the first/last per-attempt exception and include it in the thrown message:
let lastErr = null;
for (...) try { ... } catch (e) { lastErr = e; }
...
throw new Error("Failed to optimize image" + (lastErr ? `: ${lastErr.message}` : ""), { cause: lastErr });
That alone would have made this a 30-second diagnosis instead of an hour.
A clearer message like "Failed to optimize image: Cannot find package 'sharp'" would immediately point the operator at the fix.
Workaround
sudo npm install --prefix /usr/lib/node_modules/openclaw sharp --no-save
(Adds 369 packages including libvips bindings, ~80MB.) After install, the image tool works for all formats. The fix survives until the next OpenClaw upgrade.
Impact
Any Linux deployment of OpenClaw where the install path skips optional native deps has a silently broken vision pipeline. Operators see image tool calls fail and have no clear path to diagnosis without reading the OpenClaw bundled JS.
Summary
The
imagetool fails with the opaque errorFailed to optimize imageon every image in environments where the optionalsharppackage is not installed. The vision pipeline has no fallback and no clear indication that a missing native dependency is the cause.Environment
/usr/lib/node_modules/openclaw/Reproduction
sharpis not innode_modules(it is listed in OpenClaw'spackage.jsononlyBuiltDependenciesarray but is not independencies/optionalDependencies, so it can be skipped during global install).imagetool against the saved path:{ "status": "error", "tool": "image", "error": "Failed to optimize image" }This happens regardless of input format (JPEG, PNG, WebP), size, dimensions, or EXIF orientation.
Root cause
/usr/lib/node_modules/openclaw/dist/extensions/media-understanding-core/image-ops.jsdoes a dynamicimport("sharp")at runtime. When the package isn't installed, every call toresizeToJpegthrows./usr/lib/node_modules/openclaw/dist/web-media-DaFqOHhS.js'soptimizeImageToJpegfunction tries 25 size×quality combinations (5 sides × 5 qualities) and swallows every per-attempt exception withtry {} catch {}. After all 25 fail, it throws the genericFailed to optimize image— losing the underlying "sharp not found" cause entirely.So the user-facing failure is one opaque message regardless of:
Suggested fix
Either or both:
1. Make
sharpa hard dependency. It's clearly required for image attachment processing on non-macOS hosts (the only fallback issips, which is macOS-only). Listing it inonlyBuiltDependencieswithout listing it independenciesis what allows it to be skipped on Linux installs.2. Surface the underlying error. In
optimizeImageToJpeg, capture the first/last per-attempt exception and include it in the thrown message:That alone would have made this a 30-second diagnosis instead of an hour.
A clearer message like
"Failed to optimize image: Cannot find package 'sharp'"would immediately point the operator at the fix.Workaround
(Adds 369 packages including libvips bindings, ~80MB.) After install, the image tool works for all formats. The fix survives until the next OpenClaw upgrade.
Impact
Any Linux deployment of OpenClaw where the install path skips optional native deps has a silently broken vision pipeline. Operators see image tool calls fail and have no clear path to diagnosis without reading the OpenClaw bundled JS.