Skip to content

fix(deploy): upload the same Worker exports as cf when secrets are pinned - #487

Merged
graphite-app[bot] merged 1 commit into
mainfrom
fix/cf-pinned-exports-shape
Oct 19, 2026
Merged

graphite-app[bot] merged 1 commit into
mainfrom
fix/cf-pinned-exports-shape

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Fixes #460

Problem

1. void deploy          cf workers versions create --prebuilt
                        DO export: {type:"durable-object", storage:"sqlite"}
2. void secret put      PUT /scripts/{w}/secrets → Cloudflare copies v1 → 100%
3. void deploy          live version has a secret → Void's pinned uploader
                        DO export: {type, storage, state:"created"}   ← differs
                        preview_urls:false → stage [v2 @100%, v3 @0%]
                        → 100405 "versions must declare identical exports"

The first secret on a Worker moves void deploy from cf's uploader to Void's pinned-secret uploader (cf-version-runner.ts), and the two wrote exports differently:

  • Void added state: "created" to live Durable Object classes; cf leaves it out.
  • Void kept Build Output order; cf sends Worker entrypoints, then Durable Objects, then Workflows.
  • Void kept container on legacy-kv classes and sent {} for no exports; cf drops both.

With preview_urls: false, Void checks a new version by staging it at 0% beside the live one. Cloudflare only splits traffic between versions with identical exports, so every retry failed.

Fix

  • exportsFromOutput keeps its checks, then builds the entries with @cloudflare/config's convertToWranglerConfig (the converter cf uses) and orders and trims them like cf's resolveExportsUploadPayload (Workflows stay identity-only, as before).
  • On 100405 during staging, the error now says the versions declare different exports and suggests one void deploy --platform cloudflare --atomic. "Production traffic is unchanged" stays.
  • The touched 10210 hint check uses includes instead of a regex.

Note: a Worker whose live version was already uploaded by the old pinned path (with state: "created") may hit 100405 once more; the new hint tells the user to run --atomic once.

Tests

Test Old code Fix
uploads the same exports as cf for the same Build Output: runs the real cf against a fake API and compares its upload with the pinned upload (key order counts) fail pass
converts Container and transfer exports as cf does: expectation built from convertToWranglerConfig so cf drift shows up fail pass
Updated locked shapes (live secrets ×2, Sandbox lifecycle ×6) fail pass
suggests one atomic publication when the versions declare different exports fail pass

cf-version-runner.test.ts + cloudflare-deploy.test.ts: 545 passed. Typecheck, lint, format clean. Not run against a real Cloudflare account.

🤖 Generated with Claude Code

@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 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-19T04:02:40.965321Z 1c71aab New commits
ℹ️ 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

cloudflare-workers-and-pages Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://fix-cf-pinned-exports-shape-void-cloud.voidzero-docs.workers.dev (commit 564e90e)

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://1d54bb34-void-cloud.voidzero-docs.workers.dev 564e90e 2026-10-19T05:35:12.746Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://39516f64-void-cloud.voidzero-docs.workers.dev 1c71aab 2026-10-19T04:01:33.908Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://d7a9e37d-void-cloud.voidzero-docs.workers.dev d2654a4 2026-10-19T03:55:12.347Z Visit the dashboard ↗

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: d2654a48f2

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Brooooooklyn
Brooooooklyn force-pushed the fix/cf-pinned-exports-shape branch from d2654a4 to 1c71aab Compare October 19, 2026 04:00
@Brooooooklyn
Brooooooklyn requested a review from cpojer October 19, 2026 04:26
@graphite-app

graphite-app Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Merge activity

…nned (#487)

Fixes #460

## Problem

```
1. void deploy          cf workers versions create --prebuilt
                        DO export: {type:"durable-object", storage:"sqlite"}
2. void secret put      PUT /scripts/{w}/secrets → Cloudflare copies v1 → 100%
3. void deploy          live version has a secret → Void's pinned uploader
                        DO export: {type, storage, state:"created"}   ← differs
                        preview_urls:false → stage [v2 @100%, v3 @0%]
                        → 100405 "versions must declare identical exports"
```

The first secret on a Worker moves `void deploy` from cf's uploader to Void's pinned-secret uploader (`cf-version-runner.ts`), and the two wrote `exports` differently:

- Void added `state: "created"` to live Durable Object classes; cf leaves it out.
- Void kept Build Output order; cf sends Worker entrypoints, then Durable Objects, then Workflows.
- Void kept `container` on legacy-kv classes and sent `{}` for no exports; cf drops both.

With `preview_urls: false`, Void checks a new version by staging it at 0% beside the live one. Cloudflare only splits traffic between versions with identical `exports`, so every retry failed.

## Fix

- `exportsFromOutput` keeps its checks, then builds the entries with `@cloudflare/config`'s `convertToWranglerConfig` (the converter cf uses) and orders and trims them like cf's `resolveExportsUploadPayload` (Workflows stay identity-only, as before).
- On 100405 during staging, the error now says the versions declare different exports and suggests one `void deploy --platform cloudflare --atomic`. "Production traffic is unchanged" stays.
- The touched 10210 hint check uses `includes` instead of a regex.

**Note:** a Worker whose live version was already uploaded by the old pinned path (with `state: "created"`) may hit 100405 once more; the new hint tells the user to run `--atomic` once.

## Tests

| Test | Old code | Fix |
|---|---|---|
| `uploads the same exports as cf for the same Build Output`: runs the real `cf` against a fake API and compares its upload with the pinned upload (key order counts) | fail | pass |
| `converts Container and transfer exports as cf does`: expectation built from `convertToWranglerConfig` so cf drift shows up | fail | pass |
| Updated locked shapes (live secrets ×2, Sandbox lifecycle ×6) | fail | pass |
| `suggests one atomic publication when the versions declare different exports` | fail | pass |

`cf-version-runner.test.ts` + `cloudflare-deploy.test.ts`: 545 passed. Typecheck, lint, format clean. Not run against a real Cloudflare account.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@graphite-app
graphite-app Bot force-pushed the fix/cf-pinned-exports-shape branch from 1c71aab to 564e90e Compare October 19, 2026 05:33
@graphite-app
graphite-app Bot merged commit 564e90e into main Oct 19, 2026
20 checks passed
@graphite-app
graphite-app Bot deployed to cloudflare-e2e October 19, 2026 05:36 Active
@graphite-app
graphite-app Bot deleted the fix/cf-pinned-exports-shape branch October 19, 2026 05:36

This branch was successfully deployed

2 active deployments
Staging — 564e90e8 Deployed Oct 19, 2026 by graphite-app[bot] via smoke-test / smoke-test #380
cloudflare-e2e — 564e90e8 Deployed Oct 19, 2026 by graphite-app[bot] via live-e2e #2220
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.

First deploy after void secret put fails with Cloudflare 100405 (exports differ) on a Durable Object Worker

2 participants