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

  1. Compress the image first (export as JPEG/WebP, reduce dimensions) so it fits under MAX_IMAGE_BYTES.
  2. Check file.size in the picker before accepting the file and warn the user immediately.
  3. Convert PNG screenshots to JPEG (photographic content) or reduce PNG bit depth.
  4. 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

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


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/308c3d4c92092dcc. Report an issue: GitHub.