windmill-labs/windmill · error
Image has no dimensions
Error message
Image has no dimensions
What it means
normalizeImageDataUrl() loads a data URL into an HTMLImageElement and derives dimensions from naturalWidth/Height (falling back to width/height). If both are 0/falsy the image cannot be drawn or bounded, so the adapter throws this error immediately before any canvas work. It protects downstream resize/encode logic from division-by-zero and empty canvases.
Source
Thrown at frontend/src/lib/components/copilot/chat/imageUtils.ts:152
return {
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)View on GitHub (pinned to e474e8803c)
Solutions
- Inspect the data URL: verify the base64 payload is complete and the MIME type matches the data.
- For SVGs, add explicit width/height (or viewBox with fixed dimensions) before attaching.
- Ensure loadImage() awaits the 'load' event, not just element creation, before normalizing.
- Pre-convert odd formats (SVG/HEIC) to PNG/JPEG before attaching to the chat.
Example fix
// before
await normalizeImageDataUrl(svgDataUrl) // SVG without dimensions
// after
svgText = svgText.replace('<svg', '<svg width="1024" height="768"')
const fixed = 'data:image/svg+xml;base64,' + btoa(svgText)
const png = await rasterizeToPng(fixed)
await normalizeImageDataUrl(png) Defensive patterns
Strategy: validation
Validate before calling
async function hasDimensions(dataUrl: string): Promise<boolean> {
const img = new Image()
await new Promise((res, rej) => { img.onload = res; img.onerror = rej; img.src = dataUrl })
return (img.naturalWidth || img.width) > 0 && (img.naturalHeight || img.height) > 0
} Type guard
function isSizedImage(img: HTMLImageElement): boolean {
return (img.naturalWidth || img.width) > 0 && (img.naturalHeight || img.height) > 0
} Try / catch
try {
const attached = await fileToAttachedImage(file)
} catch (e) {
if (e instanceof Error && e.message === 'Image has no dimensions') {
notify('This image has no readable dimensions; try PNG or JPEG')
} else throw e
} Prevention
- Give SVGs explicit width/height before attaching
- Pre-rasterize SVG/HEIC to PNG or JPEG
- Verify base64 payloads are complete after copy/paste or truncation-prone transfers
When it happens
Trigger: loadImage() resolved but img.naturalWidth/img.width or img.naturalHeight/img.height are 0 — e.g. the data URL decoded to an empty/broken image, an SVG without intrinsic dimensions, or a still-loading image passed directly.
Common situations: Attaching an SVG pasted from a design tool with no width/height attributes; a truncated base64 payload that still decodes; images constructed programmatically before load completed.
Related errors
- Image resolution is too large
- Image file 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/2e3704b6f0408642.
Report an issue: GitHub.