windmill-labs/windmill · error
Image file is too large
Error message
Image file is too large
What it means
fileToAttachedImage() is the entry point for user-supplied image files and first enforces a byte-size budget: MAX_IMAGE_BYTES (defined in imageUtils.ts). Files larger than this are rejected before even being read into a data URL, preventing huge Blob reads and base64 inflation (base64 adds ~33%) from entering the pipeline. Unlike the pixel check (435), this fires on encoded file size before any decoding.
Source
Thrown at frontend/src/lib/components/copilot/chat/imageUtils.ts:168
const srcW = img.naturalWidth || img.width
const srcH = img.naturalHeight || img.height
if (!srcW || !srcH) throw new Error('Image has no dimensions')
if (srcW * srcH > MAX_IMAGE_PIXELS) throw new Error('Image resolution is too large')
const scale = Math.min(1, maxEdge / Math.max(srcW, srcH))
const w = Math.max(1, Math.round(srcW * scale))
const h = Math.max(1, Math.round(srcH * scale))
const canvas = document.createElement('canvas')
canvas.width = w
canvas.height = h
const ctx = canvas.getContext('2d')
if (!ctx) throw new Error('Canvas 2D context unavailable')
ctx.drawImage(img, 0, 0, w, h)
return { ...encodeCanvas(canvas), name }
}
/** Read a user-provided image file and produce a bounded, model-ready AttachedImage. */
export async function fileToAttachedImage(file: File | Blob): Promise<AttachedImage> {
if (file.size > MAX_IMAGE_BYTES) throw new Error('Image file is too large')
const name = file instanceof File ? file.name : undefined
const dataUrl = await blobToDataUrl(file)
return await normalizeImageDataUrl(dataUrl, name)
}
/** Split a data URL into its media type and base64 payload (for the Anthropic converter). */
export function parseImageDataUrl(url: string): { mediaType: string; base64: string } {
const match = /^data:([^;,]+)?(;base64)?,(.*)$/s.exec(url)
if (!match) return { mediaType: 'image/png', base64: '' }
return { mediaType: match[1] || 'image/png', base64: match[2] ? match[3] : '' }
}
/** Build the OpenAI-format image content part that all three provider paths convert from. */
export function dataUrlToImagePart(dataUrl: string): ChatCompletionContentPartImage {
return { type: 'image_url', image_url: { url: dataUrl } }
}
/** Whether any message still carries an image_url content part. */View on GitHub (pinned to e474e8803c)
Solutions
- Compress the image first (export as JPEG/WebP, reduce dimensions) so it fits under MAX_IMAGE_BYTES.
- Check file.size in the picker before accepting the file and warn the user immediately.
- Convert PNG screenshots to JPEG (photographic content) or reduce PNG bit depth.
- If the limit is genuinely too low for your use case, raise MAX_IMAGE_BYTES in imageUtils.ts, noting downstream pixel limits still apply.
Example fix
// before
await fileToAttachedImage(rawScreenshot) // 12 MB PNG
// after
if (rawScreenshot.size > MAX_IMAGE_BYTES) {
rawScreenshot = await compressToJpeg(rawScreenshot, { maxEdge: 2048, quality: 0.85 })
}
await fileToAttachedImage(rawScreenshot) Defensive patterns
Strategy: validation
Validate before calling
const MAX_IMAGE_BYTES = 10 * 1024 * 1024 // check imageUtils.ts for the exact value
if (file.size > MAX_IMAGE_BYTES) {
file = await compressToJpeg(file, { maxEdge: 2048, quality: 0.85 })
}
await fileToAttachedImage(file) Try / catch
try {
const attached = await fileToAttachedImage(file)
} catch (e) {
if (e instanceof Error && e.message === 'Image file is too large') {
const compressed = await compressToJpeg(file, { maxEdge: 2048, quality: 0.8 })
return await fileToAttachedImage(compressed)
} else throw e
} Prevention
- Check file.size in the file input's accept/change handler and warn early
- Auto-compress oversized files instead of rejecting them
- Prefer JPEG/WebP exports for screenshots over raw PNG
When it happens
Trigger: Calling addImages/fileToAttachedImage with a File or Blob whose file.size > MAX_IMAGE_BYTES — e.g. a multi-megabyte screenshot PNG, a 10MB scanned PDF page export, or an unedited camera JPEG.
Common situations: Pasting large screenshots from Retina displays; dragging photos straight from a camera SD card; programmatic uploads of uncompressed PNGs (UI mockups exported as PNG can be tens of MB).
Related errors
- Image has no dimensions
- Image resolution is too large
- result.substring(__RESULT_ERR_PREFIX.length)
- Invalid migration name '${name}': use only letters, digits,
- Unknown workspace dependencies file format: ${path}. Valid f
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/308c3d4c92092dcc.
Report an issue: GitHub.