Skip to content

fix(deploy): match Cloudflare's Worker size limit on Void Cloud - #439

Merged
Brooooooklyn merged 2 commits into
mainfrom
fix/deploy-worker-size-limit
Oct 16, 2026
Merged

Brooooooklyn merged 2 commits into
mainfrom
fix/deploy-worker-size-limit

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Problem

Void Cloud refused Workers that Cloudflare accepts. The napi.rs deploy failed with:

Deploy failed (HTTP 413): request body exceeds 67108864 bytes

@cloudflare/vite-plugin 1.64 writes Worker source maps by default. The CLI sent every Worker module, as base64, inside the deploy request, so the maps counted against the API's 64 MiB body cap.

                         Cloudflare                   Void Cloud before this PR
code limit               64 MiB uncompressed          JSON body ≤ 64 MiB, as base64
                                                        → ≈ 48 MiB raw, maps included
source maps              not counted (15 MB gz each)  counted
per module               no limit                     32 MiB
napi.rs: 26.8 MB code    ✓ accepted                   ✗ 413 (≈ 67.3 MB body)
  + 23.7 MB maps

Raising the cap does not fix it. The API Worker has 128 MB per isolate and held about two full copies of the modules: one while it parsed the body, and one in the FormData it sent to Cloudflare.

What this PR changes

Worker modules now take the same path as static assets. The API streams them to Cloudflare and never holds the whole bundle.

CLI                                  API (request)                       R2
 │ POST deploy/worker-upload-urls    │                                   │
 │   {modules:[name,size,sha256]} ──▶│ code without maps ≤ 64 MiB?       │
 │                                   │   no → 413 worker_too_large       │
 │◀── {id, urls[]} ──────────────────│ presigned PUT, size signed        │
 │ PUT module i ─────────────────────┼──────────────────────────────────▶│ deployment-inputs/{project}/{id}/{i}
 │ POST deploy {workerInput} ───────▶│ one LIST: every module present,   │
 │                                   │   exact size                      │
 │                                   │ queue {deploymentId}              │
                                     ▼
                     queue: one module open at a time
                     R2 ──▶ size + SHA-256 check ──▶ multipart body ──▶ Cloudflare
                     (FixedLengthStream; a mismatch stops the body before
                      the closing boundary, so Cloudflare gets no complete form)

Old clients keep working:

CLI ──GET /.well-known/void-platform──▶ directWorkerUpload: true ?
          yes → direct path (above)
          no  → inline workerFiles, as before (temporary, see Rollout)
          no usable answer → ask once more, then decide

A finalize retry with the same idempotency key finds the admitted operation before the upload is listed. It gets the receipt even after the operation's cleanup deleted the modules.

Decisions

Question Decision Why
Where the 64 MiB rule lives API only, when it issues upload URLs One place to update when Cloudflare changes it. A Worker that is too large fails before any byte is uploaded.
Source maps No Void limit Cloudflare counts them separately and enforces its own 15 MB gzipped limit.
Integrity SHA-256 per module, checked while streaming One R2 read per module, no buffering. A changed module never reaches Cloudflare.
Size Content-Length signed into each PUT URL, checked again by one LIST at finalize R2 enforces the declared size. One LIST costs less than a HEAD per module (napi.rs has 668 modules).
Inline path for old CLIs Kept, with its old caps Its memory limits still apply. Its 413 text now names Worker modules and says to upgrade the CLI, instead of blaming assets.
Custom Durable Object snapshots Copied and restored as streams They re-upload the user Worker, so they need the same memory bound.

Rollout

merge ──▶ staging deploys (main) ──▶ prod (fast-forward prod) ──▶ npm release X
                                                                    │
old CLIs ─────────── inline path keeps working ─────────────────────┤
new CLI + old platform (1.1.11) ── inline fallback ─────────────────┤
new CLI + new platform ─────────── direct path ─────────────────────┘
                                                                    ▼
                         later: MIN_PLATFORM_VERSION = X, delete the inline fallback

Known limits

  • Connected apps that publish with OAuth approval still send inline workerFiles. The approval digest covers inline bytes only, so they keep the 64 MiB body limit. Changing that needs module digests in the approved artifact. That is a product decision, so this PR leaves it alone.
  • Until MIN_PLATFORM_VERSION reaches the release that ships this, the new CLI keeps the inline fallback for platforms without directWorkerUpload.
  • R2 does not check SHA-256 at PUT time. Wrong bytes with the right size fail the deploy at the Cloudflare upload step, not at finalize.

Testing

Check Result
vp run check 33/33
vp test run 712 files, 13,583 tests pass
Live Cloudflare upload from workerd (Miniflare, local R2), napi.rs Worker: 668 modules, 26.8 MB code + 23.7 MB maps Cloudflare returned 200 and created the script in 9.6 s. Test script deleted.
Same upload with one module changed by one byte, same size The stream stopped with an integrity error. Cloudflare created no script.
New tests upload-URL route (limit, maps not counted, deploy-token access), finalize with workerInput (queued and inline execution, missing or wrong-size module, both fields sent, idempotent retry, reused upload id), streamed multipart (exact bytes, escaped names, mismatch, retry re-opens streams), Durable Object snapshot streaming, CLI path selection and request shapes

🤖 Generated with Claude Code

Brooooooklyn and others added 2 commits October 16, 2026 01:17
Managed deploys sent every Worker module as base64 inside the deploy
request, which the API caps at 64 MiB. Source maps, which
@cloudflare/vite-plugin 1.64 now emits by default, counted against that
cap, so a Worker with 27 MB of code and 24 MB of maps failed with HTTP 413
although Cloudflare accepts it.

The CLI now uploads Worker modules to R2 with presigned PUTs and names
them in the deploy request. The API checks Cloudflare's limit (64 MiB
without source maps) before it issues the URLs, then streams the modules
from R2 into the Cloudflare upload one at a time, checking size and
SHA-256 as the bytes pass. Old CLIs keep the inline path; the new CLI
uses the direct path only when platform discovery advertises it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…er uploads

A finalize retry with the same idempotency key now finds the admitted
operation before the API lists the upload, so it gets the receipt even
after the operation's input cleanup deleted the modules.

The CLI asks platform discovery once more when the first answer was
unusable, so one failed probe does not send a large Worker inline.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T17:43:14.247360Z a64905d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://fix-deploy-worker-size-limit-void-cloud.voidzero-docs.workers.dev (commit a64905d)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://69947101-void-cloud.voidzero-docs.workers.dev a64905d 2026-10-15T17:40:13.272Z Visit the dashboard ↗

@Brooooooklyn
Brooooooklyn merged commit 573557a into main Oct 16, 2026
20 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/deploy-worker-size-limit branch October 16, 2026 03:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant