Summary
Since the rollout of the Images text rasterization feature (IMAGES-2451, #81681765 merged 2026-08-12), passing an ArrayBuffer to env.IMAGES.input() crashes every .output() call with:
TypeError: Cannot read properties of undefined (reading 'font')
at serializeTextSource (cloudflare-internal:images-api:14:30)
at cloudflare-internal:images-api:88:47
at withSpan (cloudflare-internal:tracing-helpers:37:20)
at ImageTransformerImpl.output (cloudflare-internal:images-api:82:22)
This worked fine before the rollout (our Worker ran unchanged in production since 2026-08-14 and broke around 2026-08-25 with no deploy on our side). Changing compatibility_date does not avoid it.
Repro
export default {
async fetch(request, env) {
const body = await request.arrayBuffer();
const result = await env.IMAGES.input(body) // ArrayBuffer input
.transform({ width: 1200 }) // any transform, or none
.output({ format: 'image/jpeg' }); // -> TypeError (reading 'font')
return result.response();
},
};
Any transform combination fails identically (plain resize, segment, etc.), and the error is thrown in ~60ms, before reaching the backend.
Root cause
isTextSource() classifies the input source by elimination:
function isTextSource(source: ImageSource): source is TextRasterize {
return !(source instanceof ReadableStream);
}
An ArrayBuffer is not a ReadableStream, so it is misclassified as a text source, and serializeTextSource() dereferences source.options.font β undefined.font β TypeError.
Expected behavior
Either:
- Keep accepting raw bytes (
ArrayBuffer/TypedArray) as before β the Images binding docs say .input() "Accepts image bytes up to 20 MB from any source", and the pre-2451 implementation passed the source straight through to the form serializer, so ArrayBuffer worked in practice; or
- If only
ReadableStream is supported (as the TS types say), throw a clear ImagesError (e.g. "input must be a ReadableStream") instead of an internal TypeError about 'font' that gives no hint the input type is the problem.
A positive check for the text-source shape (e.g. typeof source.content === 'string') instead of elimination against ReadableStream would fix both.
Workaround
Wrap the buffer: env.IMAGES.input(new Blob([body]).stream()).
Impact
Silent production breakage for any deployed Worker that passed bytes rather than a stream β no deploy on the user's side, not mitigated by compatibility_date, and the error message points at fonts rather than the input type, which makes it expensive to diagnose.
Summary
Since the rollout of the Images text rasterization feature (IMAGES-2451, #81681765 merged 2026-08-12), passing an
ArrayBuffertoenv.IMAGES.input()crashes every.output()call with:This worked fine before the rollout (our Worker ran unchanged in production since 2026-08-14 and broke around 2026-08-25 with no deploy on our side). Changing
compatibility_datedoes not avoid it.Repro
Any transform combination fails identically (plain resize,
segment, etc.), and the error is thrown in ~60ms, before reaching the backend.Root cause
isTextSource()classifies the input source by elimination:An
ArrayBufferis not aReadableStream, so it is misclassified as a text source, andserializeTextSource()dereferencessource.options.fontβundefined.fontβ TypeError.Expected behavior
Either:
ArrayBuffer/TypedArray) as before β the Images binding docs say.input()"Accepts image bytes up to 20 MB from any source", and the pre-2451 implementation passed the source straight through to the form serializer, soArrayBufferworked in practice; orReadableStreamis supported (as the TS types say), throw a clearImagesError(e.g. "input must be a ReadableStream") instead of an internalTypeErrorabout'font'that gives no hint the input type is the problem.A positive check for the text-source shape (e.g.
typeof source.content === 'string') instead of elimination againstReadableStreamwould fix both.Workaround
Wrap the buffer:
env.IMAGES.input(new Blob([body]).stream()).Impact
Silent production breakage for any deployed Worker that passed bytes rather than a stream β no deploy on the user's side, not mitigated by
compatibility_date, and the error message points at fonts rather than the input type, which makes it expensive to diagnose.