linshenkx/prompt-optimizer · error · Error

FileReader is not available to decode image payload

Error message

FileReader is not available to decode image payload

What it means

After fetching image bytes, the code needs to base64-encode the ArrayBuffer. It tries Node's Buffer first; if Buffer is unavailable (browser), it falls back to FileReader.readAsDataURL. This error is thrown when neither exists — an environment with no Buffer and no FileReader (e.g. some Edge/worker runtimes, jsdom misconfig, or older Node without DOM globals).

Source

Thrown at packages/ui/src/utils/image-asset-storage.ts:108

  const bytes = new Uint8Array(ab)
  const inferredMimeType = inferMimeTypeFromBytes(bytes)
  const finalMimeType =
    mimeType && mimeType !== 'application/octet-stream'
      ? mimeType
      : inferredMimeType || mimeType || 'application/octet-stream'

  type BufferLike = {
    from: (data: ArrayBuffer) => { toString: (encoding: 'base64') => string }
  }

  const maybeBuffer = (globalThis as unknown as { Buffer?: BufferLike }).Buffer
  if (maybeBuffer && typeof maybeBuffer.from === 'function') {
    const b64 = maybeBuffer.from(ab).toString('base64')
    return { b64, mimeType: finalMimeType }
  }

  if (typeof FileReader === 'undefined') {
    throw new Error('FileReader is not available to decode image payload')
  }

  const blob = new Blob([ab], { type: finalMimeType })

  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 parsed = parseDataUrlPayload(dataUrl)
  if (!parsed?.b64) {
    throw new Error('Failed to decode image data URL payload')
  }

  return {
    b64: parsed.b64,

View on GitHub (pinned to 3e677b1d9f)

Solutions

  1. Polyfill FileReader in the environment (e.g. set globalThis.FileReader from a polyfill package in test setup)
  2. Ensure Node's Buffer global is available and untouched (don't set Buffer: undefined in tsconfig/vite config)
  3. Preload a polyfill such as 'blob-polyfill' in workers/tests
  4. Avoid this code path in workers: convert via btoa/atob or fetch as blob and use Response.arrayBuffer alternatives

Example fix

// before
// vitest test hitting fetchImagePayloadFromUrl
const payload = await normalizeImageSourceToPayload(url) // throws in node env without FileReader

// after
// vitest.setup.ts
import { FileReader } from 'blob-polyfill'
if (typeof globalThis.FileReader === 'undefined') globalThis.FileReader = FileReader
const payload = await normalizeImageSourceToPayload(url)
Defensive patterns

Strategy: fallback

Validate before calling

if (typeof FileReader === 'undefined' && typeof Buffer === 'undefined') {
  await installFileReaderPolyfill() // e.g. blob-polyfill
}

Type guard

const canEncodePayload = (): boolean =>
  (typeof Buffer !== 'undefined' && typeof Buffer.from === 'function') ||
  typeof FileReader !== 'undefined'

Try / catch

try { await normalizeImageSourceToPayload(url) } catch (e) { if (e.message.includes('FileReader is not available')) { await polyfillFileReader(); return retry() } throw e }

Prevention

When it happens

Trigger: Running normalizeImageSourceToPayload / fetchImagePayloadFromUrl in a Web Worker or SSR runtime where global Buffer is absent or Buffer.from is not a function and globalThis.FileReader is undefined; test environments (jest/jsdom) that don't polyfill FileReader.

Common situations: Server-side rendering in Node with Buffer tree-shaken away or shadowed; Vitest/Jest with a minimal environment; Web Workers in Safari or older runtimes lacking FileReader; exotic runtimes like certain edge functions.

Related errors


AI-assisted analysis of linshenkx/prompt-optimizer@3e677b1d9f (2026-08-27). Data as JSON: /api/errors/bea10444f4638101. Report an issue: GitHub.