TL;DR: Do not proxy large uploads through the worker. Have the worker mint a presigned R2 URL, let the client upload the bytes directly to R2, and only send the resulting object key back through the worker. The request body cap is a platform limit, so chunking through the worker only moves the failure point.

```text
workerd error: Request exceeds the maximum size limit on upload
```

1. Confirm the threshold. Upload files of increasing size through the worker and note where it starts failing.
   Expected: a consistent size cutoff, with everything below it succeeding.

2. Check the client enforces the same cutoff before sending. Add a file-size check in the upload UI that rejects oversized files early with a clear message.
   Expected: users get an immediate local error instead of a failed upload.

3. Switch to direct-to-R2 uploads. The worker generates a presigned URL for the target object and returns it to the client:
   ```js
   const url = await env.MY_BUCKET.createPresignedUrl(key);
   return Response.json({ uploadUrl: url.href });
   ```
   Expected: the client PUTs the file bytes straight to R2, bypassing the worker's body cap entirely.

4. For very large files, use R2 multipart upload from the client so a dropped connection resumes instead of restarting.
   Expected: multi-gigabyte uploads complete reliably.

5. Keep the worker in the loop only for metadata. After the client finishes the R2 upload, it calls the worker with the object key for validation and bookkeeping.
   Expected: the worker only ever sees small JSON, never the file bytes.

6. Verify end to end with a file well above the old cutoff.
   Expected: the upload succeeds and the object appears in the bucket.

## Use this when
- uploads through a worker fail above a consistent size threshold
- video, dataset, backup, or archive uploads die with the size error
- you are proxying multipart form data through the worker to storage
- the same upload succeeds when sent directly to storage but fails through the worker

## Not for this skill when
- small uploads fail too (that is a code or auth bug, not the size cap)
- the error is about response size rather than request size
- you need the worker to inspect or transform the bytes (then chunk through the worker in small pieces instead)
- the failure is a timeout on slow uploads rather than a size rejection

## Variant phrasings
- Cloudflare Worker upload too large error
- "Request exceeds the maximum size limit" upload
- worker rejects large file upload
- 413 through Cloudflare Worker upload
- file upload fails over size limit worker

## Why it happens
Workers cap how large a request body they will accept, and the cap is lower on the free plan. Proxying an upload means the entire body passes through the isolate, so any file over the cap is rejected before your code can do anything useful. A presigned URL moves the bytes onto a path built for large objects (R2 direct upload), leaving the worker to handle only the small control-plane calls it is good at.

## Edge cases
- Presigned URLs expire. Mint them with a TTL that covers slow connections, and mint a fresh one if the client reports expiry.
- Multipart form parsing in the worker still buffers the body. Do not parse the form in the worker as a workaround; go direct to R2.
- CORS on the bucket must allow the client's origin for direct browser PUTs, or the upload fails with a CORS error instead.
- Validate after upload. Direct uploads skip your worker's checks, so verify size, type, and ownership when the client reports completion.
- Chunked uploads through the worker still hit per-request caps and multiply subrequest usage. Direct upload is the fix, not smaller chunks through the worker.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_LVuCdqMuzYNXrn4hCrrQpQ
