Adding a single KV cache write broke my Worker — and it didn't throw a single error to the caller.
I run a Korean D2C ad-ops pipeline where one Worker fans out performance checks across ~400 ad accounts per request. The math looked fine: 400 accounts × 2 API calls = 800 subrequests, safely under Cloudflare's hard 1000-per-invocation ceiling. Then I added KV writes to cache each result. 400 × 3 = 1200. The Worker silently stopped processing the last ~200 accounts. No 5xx. No exception propagated. Just missing data. It took two days on wrangler tail to surface this line:
workers/runtime/fetch: subrequest count exceeded limit of 1000
The thing that makes this limit especially tricky for fan-out patterns: it resets per invocation, not per batch or queue message. And the count includes more than you'd expect — every fetch(), every KV get/put, every R2 operation, every D1 query, every Durable Object stub call. The one useful exception: Queue.sendBatch() does not count against it. That's the escape hatch the fix depends on.
The architectural answer is splitting the fan-out trigger from the fan-out work. The entry Worker receives the request and immediately calls env.QUEUE.sendBatch() with one message per account — zero upstream fetches, zero KV writes, well under any limit. Each queue consumer invocation then handles a small batch of messages (I run max_batch_size = 10), doing its 3 subrequests per account in isolation. Ten messages × 3 subrequests = 30 per invocation. The ceiling becomes irrelevant.
The tradeoff worth knowing before you commit to this pattern: Queues are fire-and-forget. If your use case requires returning all 400 account summaries in a single synchronous HTTP response — like a live dashboard — this approach alone won't get you there. That's a different problem requiring a Durable Object as an aggregation point, which adds its own subrequest considerations.
I wrote up the full breakdown — including the Durable Object aggregation pattern for synchronous fan-out, the exact wrangler.toml consumer config, and the complete subrequest reference table — over on dailymanuallab.com.
Top comments (0)