windmill-labs/windmill · error

Image resolution is too large

Error message

Image resolution is too large

What it means

normalizeImageDataUrl() enforces a hard pixel-budget: MAX_IMAGE_PIXELS = 40,000,000 (40 MP). If srcW * srcH exceeds it, the image is rejected before canvas resizing because decoding such an image would allocate excessive memory (canvas decode bombs). The error is thrown before any downscaling is attempted — the budget is checked on source pixels, not output pixels.

Source

Thrown at frontend/src/lib/components/copilot/chat/imageUtils.ts:153

		dataUrl: (ctx ? flat : canvas).toDataURL('image/jpeg', 0.82),
		mediaType: 'image/jpeg'
	}
}

/**
 * Downscale a data URL to ≤ MAX_IMAGE_EDGE on its longest side and re-encode to
 * png/jpeg. Used by both the file-attach path and the screenshot tool.
 */
export async function normalizeImageDataUrl(
	dataUrl: string,
	name?: string,
	maxEdge: number = MAX_IMAGE_EDGE
): Promise<AttachedImage> {
	const img = await loadImage(dataUrl)
	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)

View on GitHub (pinned to e474e8803c)

Solutions

  1. Downscale the image before attaching, e.g. resize to ≤ 40MP (or simply ≤ 6000×6000) with canvas or a tool.
  2. Export/capture at lower resolution (camera 'storage saver' mode, scanner DPI setting).
  3. Convert to JPEG at reduced dimensions client-side before calling fileToAttachedImage.
  4. If legitimately needed, raise MAX_IMAGE_PIXELS in imageUtils.ts:29 — but weigh memory cost on low-end devices.

Example fix

// before
const img = await fileToAttachedImage(hugePhotoFile) // 80 MP
// after
const resized = await downscaleToMaxPixels(hugePhotoFile, 40_000_000)
const img = await fileToAttachedImage(resized)
Defensive patterns

Strategy: validation

Validate before calling

const MAX_IMAGE_PIXELS = 40_000_000
async function withinPixelBudget(file: Blob): Promise<boolean> {
  const bmp = await createImageBitmap(file)
  const ok = bmp.width * bmp.height <= MAX_IMAGE_PIXELS
  bmp.close()
  return ok
}

Try / catch

try {
  const attached = await fileToAttachedImage(file)
} catch (e) {
  if (e instanceof Error && e.message === 'Image resolution is too large') {
    notify('Image exceeds 40 megapixels — please resize before attaching')
  } else throw e
}

Prevention

When it happens

Trigger: Attaching an image whose naturalWidth * naturalHeight > 40MP, e.g. a 50MP camera photo, a high-DPI scan, or a stitched panorama, via fileToAttachedImage or directly via normalizeImageDataUrl.

Common situations: Modern smartphone photos in full resolution (48–200MP); microscope/aerial imagery; drag-dropping a RAW-exported JPEG into the chat.

Related errors


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