Skip to content

fix(image): surface underlying error when image optimization fails#6

Open
suboss87 wants to merge 56 commits intomainfrom
fix/image-optimize-surface-underlying-error
Open

fix(image): surface underlying error when image optimization fails#6
suboss87 wants to merge 56 commits intomainfrom
fix/image-optimize-surface-underlying-error

Conversation

@suboss87
Copy link
Copy Markdown
Owner

@suboss87 suboss87 commented Apr 28, 2026

Summary

When sharp is not installed (common on Linux global installs or slim Docker images) every resizeToJpeg / resizeToPng call inside the optimization loops throws MODULE_NOT_FOUND. The loop silently swallows all 25 (JPEG) or 20 (PNG) errors via an empty catch {}, so the final throw surfaces only a generic "Failed to optimize image" with no diagnostic information. Users have no way to tell whether the failure is a missing native dependency, an unsupported format, or a memory limit.

Root cause

optimizeImageToJpeg in src/web/media.ts (lines ~454-477) and optimizeImageToPng in src/media/image-ops.ts (lines ~429-454) both had:

} catch {
  // Continue trying other size/quality combinations
}
// ... after loop exhausted:
throw new Error("Failed to optimize image");

The catch block discarded the error entirely and the terminal throw provided no context.

Fix

Capture the last loop error in lastResizeErr. After the loop, include its message in the thrown error and attach it as cause:

let lastResizeErr: unknown;
// ... in loop:
} catch (err) {
  lastResizeErr = err;
}
// ... after loop:
const cause = lastResizeErr instanceof Error ? lastResizeErr : undefined;
const detail = lastResizeErr instanceof Error ? lastResizeErr.message : typeof lastResizeErr === "string" ? lastResizeErr : "";
throw new Error(
  detail ? `Failed to optimize image: ${detail}` : "Failed to optimize image",
  cause ? { cause } : undefined,
);

This is minimal -- no behavior change for successful paths, and the smallest fallback return is still reached before the throw when any combination succeeds.

Test plan

  • Three new regression tests in src/web/media.test.ts (image optimization error surfacing describe block): mock resizeToJpeg to always reject with a specific Error, verify the caught error message includes the underlying cause, verify .cause is set, verify non-Error thrown values fall back to the generic message.
  • All 27 tests in src/web/media.test.ts pass (vitest run src/web/media.test.ts)

Closes openclaw#73148


Generated by Claude Code


Open in Devin Review

claude added 30 commits April 1, 2026 15:34
claude and others added 26 commits April 18, 2026 03:46
When all size/quality combinations in optimizeImageToJpeg or optimizeImageToPng
fail (e.g. because sharp is not installed), the thrown error now includes the
message and cause from the last resize attempt instead of a generic opaque
string. Adds regression tests for the JPEG path.

Closes openclaw#73148
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Image tool: opaque "Failed to optimize image" when sharp is not installed

2 participants