cloudflare / cloudflare/workerd

🐛 Bug Report — Runtime APIs: Images binding crashes with "Cannot read properties of undefined (reading 'font')" when input() is given an ArrayBuffer

Open
#7,126 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
8.7k
Forks
739
Avg merge
2d 20h
Merged PRs (30d)
174

Description

## 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

```js
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:

```ts
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:

1. 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
2. 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.

Contributor guide

Open the contributing guide

Research direction

Start with the Images binding's isTextSource() and serializeTextSource() paths, then reproduce the failure using the ArrayBuffer example in the issue and compare it with the documented ReadableStream workaround. Done means ArrayBuffer or TypedArray input works again, or unsupported inputs produce a clear ImagesError instead of the font-related TypeError.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.