{"record":{"id":"33c70b6a6dc0821a","repo":"windmill-labs/windmill","slug":"image-resolution-is-too-large","errorCode":null,"errorMessage":"Image resolution is too large","messagePattern":"Image resolution is too large","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/imageUtils.ts","lineNumber":153,"sourceCode":"\t\tdataUrl: (ctx ? flat : canvas).toDataURL('image/jpeg', 0.82),\n\t\tmediaType: 'image/jpeg'\n\t}\n}\n\n/**\n * Downscale a data URL to ≤ MAX_IMAGE_EDGE on its longest side and re-encode to\n * png/jpeg. Used by both the file-attach path and the screenshot tool.\n */\nexport async function normalizeImageDataUrl(\n\tdataUrl: string,\n\tname?: string,\n\tmaxEdge: number = MAX_IMAGE_EDGE\n): Promise<AttachedImage> {\n\tconst img = await loadImage(dataUrl)\n\tconst srcW = img.naturalWidth || img.width\n\tconst srcH = img.naturalHeight || img.height\n\tif (!srcW || !srcH) throw new Error('Image has no dimensions')\n\tif (srcW * srcH > MAX_IMAGE_PIXELS) throw new Error('Image resolution is too large')\n\tconst scale = Math.min(1, maxEdge / Math.max(srcW, srcH))\n\tconst w = Math.max(1, Math.round(srcW * scale))\n\tconst h = Math.max(1, Math.round(srcH * scale))\n\tconst canvas = document.createElement('canvas')\n\tcanvas.width = w\n\tcanvas.height = h\n\tconst ctx = canvas.getContext('2d')\n\tif (!ctx) throw new Error('Canvas 2D context unavailable')\n\tctx.drawImage(img, 0, 0, w, h)\n\treturn { ...encodeCanvas(canvas), name }\n}\n\n/** Read a user-provided image file and produce a bounded, model-ready AttachedImage. */\nexport async function fileToAttachedImage(file: File | Blob): Promise<AttachedImage> {\n\tif (file.size > MAX_IMAGE_BYTES) throw new Error('Image file is too large')\n\tconst name = file instanceof File ? file.name : undefined\n\tconst dataUrl = await blobToDataUrl(file)\n\treturn await normalizeImageDataUrl(dataUrl, name)","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/imageUtils.ts#L135-L171","documentation":"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.","triggerScenarios":"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.","commonSituations":"Modern smartphone photos in full resolution (48–200MP); microscope/aerial imagery; drag-dropping a RAW-exported JPEG into the chat.","solutions":["Downscale the image before attaching, e.g. resize to ≤ 40MP (or simply ≤ 6000×6000) with canvas or a tool.","Export/capture at lower resolution (camera 'storage saver' mode, scanner DPI setting).","Convert to JPEG at reduced dimensions client-side before calling fileToAttachedImage.","If legitimately needed, raise MAX_IMAGE_PIXELS in imageUtils.ts:29 — but weigh memory cost on low-end devices."],"exampleFix":"// before\nconst img = await fileToAttachedImage(hugePhotoFile) // 80 MP\n// after\nconst resized = await downscaleToMaxPixels(hugePhotoFile, 40_000_000)\nconst img = await fileToAttachedImage(resized)","handlingStrategy":"validation","validationCode":"const MAX_IMAGE_PIXELS = 40_000_000\nasync function withinPixelBudget(file: Blob): Promise<boolean> {\n  const bmp = await createImageBitmap(file)\n  const ok = bmp.width * bmp.height <= MAX_IMAGE_PIXELS\n  bmp.close()\n  return ok\n}","typeGuard":null,"tryCatchPattern":"try {\n  const attached = await fileToAttachedImage(file)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Image resolution is too large') {\n    notify('Image exceeds 40 megapixels — please resize before attaching')\n  } else throw e\n}","preventionTips":["Downscale on ingest with createImageBitmap + canvas before attaching","Check dimensions in the file picker via an Image element and reject early","Document the 40MP limit in the attachment UI hint"],"tags":["image","validation","resource-limit"],"backgroundTag":"image-resolution-too-large","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}