linshenkx/prompt-optimizer · warning · Error
Failed to decode image data URL
Error message
Failed to decode image data URL
What it means
After fetching image bytes, the blob is read via FileReader.readAsDataURL and the resulting data URL must match /^data:.*?;base64,(.*)$/u. If no base64 segment is captured (b64 is empty), the decode is considered failed. This is a browser-side encoding anomaly, not an HTTP failure.
Source
Thrown at packages/ui/src/composables/app/useAppPromptGardenImport.ts:766
}
if (typeof FileReader === 'undefined') {
throw new Error('FileReader is not available to decode images')
}
const blob = await resp.blob()
const actualMime = blob.type || mimeType
const dataUrl = await new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onerror = () => reject(new Error('Failed to read image blob'))
reader.onload = () => resolve(String(reader.result || ''))
reader.readAsDataURL(blob)
})
const match = dataUrl.match(/^data:.*?;base64,(.*)$/u)
const b64 = match ? match[1] : ''
if (!b64) {
throw new Error('Failed to decode image data URL')
}
return { b64, mimeType: actualMime || 'application/octet-stream' }
}
const dedupeStrings = (items: string[]): string[] => {
return Array.from(new Set(items.filter(Boolean)))
}
const buildAssetSourceMetadata = (snapshot: GardenSnapshot): { prompt?: string } => {
if (snapshot.prompt.format !== 'text') {
return {}
}
const prompt = typeof snapshot.prompt.text === 'string' ? snapshot.prompt.text.trim() : ''
if (!prompt) return {}
return { prompt }
}
View on GitHub (pinned to 3e677b1d9f)
Solutions
- Log the actual dataUrl string to see what readAsDataURL produced; check for 'data:,' or an empty payload
- Verify content-type of the image response is a normal image mime (image/png, image/jpeg); fix the server's header if wrong
- Check the response body length (content-length) to rule out empty 200 responses
- As a fallback, convert via arrayBuffer + btoa instead of FileReader for deterministic base64 encoding
Example fix
// before reader.readAsDataURL(blob) const b64 = dataUrl.match(/^data:.*?;base64,(.*)$/u)?.[1] ?? '' // after const buf = new Uint8Array(await blob.arrayBuffer()) let bin = '' buf.forEach(b => bin += String.fromCharCode(b)) const b64 = btoa(bin)
Defensive patterns
Strategy: fallback
Validate before calling
if (blob.size === 0) throw new Error('Empty image blob')
if (!/^image\//.test(blob.type)) console.warn('Unexpected image mime:', blob.type) Type guard
const isBase64DataUrl = (u: string): boolean => /^data:.*?;base64,.+/u.test(u)
Try / catch
try { return decodeViaFileReader(blob) } catch { return decodeViaArrayBuffer(blob) /* btoa fallback */ } Prevention
- Prefer blob.arrayBuffer() + btoa over FileReader for deterministic base64
- Reject empty blobs before reading
- Ensure image responses carry correct image/* content-type headers
When it happens
Trigger: readAsDataURL produced a data URL without a base64 payload — e.g. an empty or tiny blob, a non-standard mime yielding 'data:,', or browser/encoding edge cases (unusual content-types, blob closed prematurely) that yield a data URL not matching the regex.
Common situations: Zero-byte response bodies with 200 status; content-type headers that make the browser emit a plain (non-base64) data URL; unusual mime types from object storage; race where the blob handle was revoked before reading.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Example image request failed: ${resp.status}
- Image result evaluation requires at least one output image e
- Image compare evaluation requires at least two snapshots wit
- Image compare evaluation requires every compared snapshot to
- No valid image evidence could be resolved for evaluation.
AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27).
Data as JSON: /api/errors/26b7637b02ea46da.
Report an issue: GitHub.