Skip to content

fix(deploy): resolve the workers.dev URL after a first publish over a draft Worker - #641

Merged
cpojer merged 4 commits into
voidzero-dev:mainfrom
magurotuna:fix/573-atomic-publish-no-url
Oct 30, 2026
Merged

cpojer merged 4 commits into
voidzero-dev:mainfrom
magurotuna:fix/573-atomic-publish-no-url

Conversation

@magurotuna

Copy link
Copy Markdown
Member

Fixes #573

Problem

If you run void secret put or void secret sync before the first void deploy, the deploy fails with atomic-output-invalid (or bootstrap-output-invalid in the non-atomic mode). The new version is already live, but workers.dev stays disabled, and the readiness check never runs.

The secret commands create a draft Worker because Cloudflare stores secrets on a Worker. The draft has workers.dev disabled. Cloudflare does not return a URL when it publishes over this draft. Void needs the account subdomain to build the readiness URL, but a first deploy has no configured or cached subdomain. Void enables workers.dev later, in the trigger sync, so the deploy stops before workers.dev is ever enabled.

What changed

If the publish returns no URL, Void asks Cloudflare for the account subdomain and continues. Some points that the code does not show:

  • The lookup runs only when it is needed. It runs only if the URL is missing and the trigger sync in this deploy will enable workers.dev. Other deploys make no extra API call. If workers.dev stays disabled, a URL would not help, because the probe could not reach it.
  • The probe sends Cloudflare Access credentials, so the host must be correct. Void checks the uploader pin before it reads the session token. Void also fixes the compliance region before the build runs project code. A build cannot change compliance_region and send the probe to a different host. For FedRAMP High, the host gets .fed, as in Wrangler.
  • A failed lookup fails safely. The deploy stops as before. The error message now says that the version is live, and it tells you how to recover.

The lookup needs no paid product, so Workers Free deploys still work. The docs do not change.

Tests

The tests mock Cloudflare. The issue scenario (a draft Worker, and a publish with no URL) failed before the fix in both modes and passes after it. Other tests cover the cases that must skip the lookup, the FedRAMP host, the region pin, and a changed uploader.

Choices to check

  • I did not test against live Cloudflare. The fix assumes that the publish over a draft returns an empty urls list (as the issue reports), and that the subdomain endpoint returns the label without the region suffix (as Wrangler assumes).
  • An existing Worker that uploads a version without a preview URL still needs CLOUDFLARE_WORKERS_SUBDOMAIN. I did not add the lookup there, because it changes which host receives Access credentials. That belongs in a separate PR.
  • I did not use the output of the trigger sync to find the URL. That output is not a stable format, and the change would publish triggers before the URL check.

AI disclosure: I used Claude to write code and this PR. I reviewed them.

@magurotuna
magurotuna marked this pull request as ready for review October 30, 2026 04:06
cpojer
cpojer previously approved these changes Oct 30, 2026

@cpojer cpojer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

magurotuna and others added 4 commits October 30, 2026 16:34
… draft Worker

`void secret put` creates a draft Worker with workers.dev disabled. The
next first deploy publishes through the pinned version upload, which
reports a version id but no URL. Without a configured or cached account
subdomain, `bootstrapFirstDeployment` returned `atomic-output-invalid`
or `bootstrap-output-invalid` after the version was live, so trigger
synchronization and the readiness check never ran.

If the publish reports no URL and the desired config enables
workers.dev, Void now checks the pinned uploader and reads the account
subdomain from `GET /accounts/{account_id}/workers/subdomain`. It then
continues to trigger synchronization and readiness on the resolved URL.
If the lookup fails, the old result remains. The error message now
names the live version and points to `CLOUDFLARE_WORKERS_SUBDOMAIN`
when only the URL is missing.

Fixes voidzero-dev#573
- Add the `.fed` label to the looked-up subdomain for FedRAMP High, as
  Wrangler does. The lookup resolves the compliance region with the same
  rules as the pinned API base. Before this change, readiness and its
  Access headers went to the public-region host.
- Return a `CloudflareWorkersDevSubdomainLookup` result from the lookup.
  A changed uploader inside the lookup now gives `uploader-changed` with
  `rollback: 'unsafe'`, not an unknown-URL error.
- Skip the lookup when trigger synchronization does not publish
  `workers_dev`, because a preserved snapshot leaves workers.dev off.
- For a non-atomic first deploy, tell the user to turn on workers.dev in
  the dashboard before they retry. Show the FedRAMP High subdomain form.
- Add tests for the region suffix, the CLI wiring, the guards, and the
  published trigger config.
Pin the workers.dev compliance region with the API base, before project
code runs, and pass it to the lookup. The lookup no longer reads the root
config again after the build, so a build cannot change the host that
receives the Access readiness headers.

If the region does not resolve (a direct API base with an invalid or
conflicting region), the lookup reports no URL instead of guessing a host.

Add a test for the usual CLI message, which preserves unset traffic
settings. Split the bootstrap recovery line into two sentences.
@cpojer
cpojer force-pushed the fix/573-atomic-publish-no-url branch from d88eba9 to dc7c7a1 Compare October 30, 2026 07:43
@cpojer
cpojer merged commit a8428d3 into voidzero-dev:main Oct 30, 2026
18 checks passed
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.

Initial deploy fails after bootstrapping secrets: atomic publish returns no URL

2 participants