TL;DR
Queue messages were being dropped because they were over platform limits -> wanted to handle typed / tagged errors from queue binding but it requires parsing/relying on implicit logic coded in error message strings. Request: please throw or return typed errors + document them so that we can safely rely on them in prod
What we'd like
-
Typed, coded errors for producer-limit failures, with stable code values and a documented catalog, e.g.:
QUEUE_MESSAGE_TOO_LARGE
QUEUE_BATCH_TOO_LARGE
QUEUE_BATCH_TOO_MANY_MESSAGES
QUEUE_THROUGHPUT_EXCEEDED (429 / "Too Many Requests")
Distinguishable via instanceof and/or a stable error.code, with structured fields (limit, actual) rather than only interpolating them into a human string.
-
A first-party size helper so producers don't reverse-engineer how the platform computes serialized size (content-type-dependent v8/json encoding + ~100 bytes internal metadata), e.g. queue.calculateMessageSize(body, options?), or a documented exact formula. This is already a recurring community question (e.g. "how to calculate queue message size the way CF does").
-
Document all producer errors (message size, batch size, batch count, throughput/429) on the Limits and JavaScript APIs pages, including whether each is retryable.
Why it matters
A common, correct producer pattern is the transactional outbox: persist events, then relay them to a queue. If one event can never be sent (e.g. it exceeds 128 KB), the producer must classify the failure as permanent vs transient to decide between dead-lettering and retrying.
Today that decision can only be made by substring-matching English error text. Get it wrong — treat a permanent failure as transient — and the unsendable message becomes a head-of-line poison pill that blocks delivery for everything behind it and drives an infinite retry loop. Typed errors with stable codes make the permanent/transient split reliable; a size helper lets producers guard pre-flight and avoid the failed round-trip entirely.
Current behavior
Queue.send() / Queue.sendBatch() reject with a plain Error when a producer-side limit is exceeded — error.name === "Error", error.code === undefined, no own enumerable properties. The only programmatic signal is the message string, and the wording is inconsistent:
| Trigger |
Message |
message > 128 KB (send) |
Queue send failed: message length of 200029 bytes exceeds limit of 128000 |
| message > 128 KB inside a batch |
message in batch has length 331077 bytes which exceeds single message size limit of 128000 bytes |
| batch total bytes over cap |
Queue sendBatch failed: batch size of 360116 bytes exceeds limit of 256000 |
| batch count > 100 |
Queue sendBatch failed: batch message count of 101 exceeds limit of 100 |
Note the same 128 KB limit is worded two different ways depending on send vs sendBatch — exactly why string-matching is unsafe.
There is also a docs-vs-runtime discrepancy: docs state a 256 KB batch limit, but the local broker enforces the check at 288 KB (256 KB + ~32 KB) while the error text still reports 256000. Clarifying the authoritative number in both the docs and the error text would help.
Environment
workerd / Wrangler / Miniflare (local broker constants: per-message 128000, batch count 100, batch bytes 288000).
- Production Queues exhibits the same untyped-error behavior.
TL;DR
Queue messages were being dropped because they were over platform limits -> wanted to handle typed / tagged errors from queue binding but it requires parsing/relying on implicit logic coded in error message strings. Request: please throw or return typed errors + document them so that we can safely rely on them in prod
What we'd like
Typed, coded errors for producer-limit failures, with stable
codevalues and a documented catalog, e.g.:QUEUE_MESSAGE_TOO_LARGEQUEUE_BATCH_TOO_LARGEQUEUE_BATCH_TOO_MANY_MESSAGESQUEUE_THROUGHPUT_EXCEEDED(429 / "Too Many Requests")Distinguishable via
instanceofand/or a stableerror.code, with structured fields (limit,actual) rather than only interpolating them into a human string.A first-party size helper so producers don't reverse-engineer how the platform computes serialized size (content-type-dependent
v8/jsonencoding + ~100 bytes internal metadata), e.g.queue.calculateMessageSize(body, options?), or a documented exact formula. This is already a recurring community question (e.g. "how to calculate queue message size the way CF does").Document all producer errors (message size, batch size, batch count, throughput/429) on the Limits and JavaScript APIs pages, including whether each is retryable.
Why it matters
A common, correct producer pattern is the transactional outbox: persist events, then relay them to a queue. If one event can never be sent (e.g. it exceeds 128 KB), the producer must classify the failure as permanent vs transient to decide between dead-lettering and retrying.
Today that decision can only be made by substring-matching English error text. Get it wrong — treat a permanent failure as transient — and the unsendable message becomes a head-of-line poison pill that blocks delivery for everything behind it and drives an infinite retry loop. Typed errors with stable codes make the permanent/transient split reliable; a size helper lets producers guard pre-flight and avoid the failed round-trip entirely.
Current behavior
Queue.send()/Queue.sendBatch()reject with a plainErrorwhen a producer-side limit is exceeded —error.name === "Error",error.code === undefined, no own enumerable properties. The only programmatic signal is the message string, and the wording is inconsistent:send)Queue send failed: message length of 200029 bytes exceeds limit of 128000message in batch has length 331077 bytes which exceeds single message size limit of 128000 bytesQueue sendBatch failed: batch size of 360116 bytes exceeds limit of 256000Queue sendBatch failed: batch message count of 101 exceeds limit of 100Note the same 128 KB limit is worded two different ways depending on
sendvssendBatch— exactly why string-matching is unsafe.There is also a docs-vs-runtime discrepancy: docs state a 256 KB batch limit, but the local broker enforces the check at 288 KB (256 KB + ~32 KB) while the error text still reports
256000. Clarifying the authoritative number in both the docs and the error text would help.Environment
workerd/ Wrangler / Miniflare (local broker constants: per-message128000, batch count100, batch bytes288000).