Skip to content

Deploy to Cloudflare: ZodError on previews_base_config.deploy_command aborts every submit, including Cloudflare's own templates #70

Description

@thankywal

What version of wrangler are you using?

Not applicable — this is the dashboard's Deploy to Cloudflare flow, no local wrangler involved.

What operating system and version are you using?

macOS, Chrome 148–150.

Please provide a link to a minimal reproduction

https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/main/hello-world-do-template

Describe the Bug

Pressing Deploy on the Deploy to Cloudflare setup form throws an uncaught ZodError and the submission aborts. It reproduces with Cloudflare's own templates, so it is not specific to any one repository.

Uncaught (in promise) ZodError: [
  {
    "expected": "string",
    "code": "invalid_type",
    "path": [
      "previews_base_config",
      "deploy_command"
    ],
    "message": "Invalid input: expected string, received undefined"
  }
]
    at at (cf-useBuilds.Q3C8LSNY.js:3:1874)
    at Hl (cf-ConfigureTemplate.CN_WXn13.js:38:62815)
    at Zl (cf-ConfigureTemplate.CN_WXn13.js:38:68824)
    at async onSubmit (cf-ConfigureTemplate.CN_WXn13.js:38:74781)
    at async cf-authenticated-app.T9NSyoF.js:22:22118

Steps to reproduce

  1. Open the link above while signed in to an affected account.
  2. Fill in the form (the defaults are fine).
  3. Press Deploy.
  4. The form shows "Setting up your repository. This may take a few seconds…", then returns to its previous state. The ZodError above is in the console.

What the user is left with. This is the part worth prioritising: the flow fails silently. By the time it throws, the dashboard has already created a Worker from the placeholder template and a repository in the user's GitHub account. What remains is:

  • A repository containing exactly two files, README.md and the parsed wrangler config, committed by cloudflare-workers-and-pages[bot] with the message Uploading template. (a working import commits as cloudflare[bot] with source repo import and contains the full tree).
  • No queued build — Workers Builds is never configured, so nothing ever builds.
  • The placeholder Worker still deployed and answering Hello world.
  • A dashboard that reports success.

Nothing surfaces an error to the user, so people reasonably believe the install worked and go looking for the fault in their own project.

Scope: what we varied

We chased this for a day assuming it was our repository. It is not. Each row is a real attempt:

Repository Cloudflare account GitHub account Result
Our app, current A 1 ZodError
Our app, byte-exact tree that imported successfully on 11 Aug B (created that day) 2 (created that day) ZodError
Our app, with the deploy script removed so the form falls back to its documented defaults A 1 ZodError
cloudflare/templateshello-world-do-template A 1 ZodError
cloudflare/templateshello-world-do-template C 3 ZodError

Four repositories, three Cloudflare accounts, three GitHub identities, two browsers. The error follows none of them.

The second row is the useful control: that tree is byte-for-byte the one Cloudflare imported successfully on 2026-08-11 05:37 UTC (95 files, cloudflare[bot], source repo import). Published unchanged as a separate repository and deployed again the next day on a brand new account, it fails. Same bytes, different day, different outcome.

Analysis

From cf-ConfigureTemplate.CN_WXn13.js, the build settings sent to the API are assembled as:

let m = a ? !!i.enable_preview_builds : !!i.non_production_branch_builds,
    h = a ?   i.preview_command        :   i.non_production_branch_deploy_command;
return {
  script_tag: e,
  git_repository: { ...n, branch: t },
  production_settings: { ...d, deploy_command: o },
  previews_enabled: c,
  previews_base_config: { ...d, deploy_command: s }   // s ← h, undefined here
}

and the form's default values are:

[jo]: n && r && `build`  in n ? `${r} run build`  : ``,
[Fo]: n && r && `deploy` in n ? `${r} run deploy` : `npx wrangler deploy`,
[ji]: `npx wrangler versions upload`,   // non_production_branch_deploy_command
[Uo]: `npx wrangler preview`,           // preview_command

So build_command and the production deploy_command are derived from the repository's package.json and are always populated — both are visibly filled in on the form in every failing case. previews_base_config.deploy_command comes only from a form field: preview_command when the account has Worker Previews enabled, otherwise non_production_branch_deploy_command. Neither field is rendered on the deploy-to-workers template form, and the value reaches the schema as undefined.

Two things point at the Worker Previews rollout rather than at anything a user controls:

  • Affected accounts take the createPath: 'worker_previews' branch during build-token creation, which selects i.preview_command — the field with no input on this form.
  • Both defaults are hardcoded in the bundle. Nothing in a repository can supply this value, which is consistent with the documented behaviour that Workers Builds does not honour build configuration from the Wrangler file.

Suggested fix

Defaulting h to `npx wrangler versions upload` when the form does not collect it would restore the flow, since that is already the documented default for the non-production branch deploy command.

Separately, and regardless of this specific bug: it would help a lot if a failed submit did not leave behind a two-file repository, an unconfigured build and a placeholder Worker under a success message. The silent half-completed state cost far more time than the error itself.

Please provide any relevant error logs

Related, and possibly the same root cause seen from the other end: #31 reports the two-file repository and the Worker stuck on the Hello World placeholder, which is exactly the state this ZodError leaves behind.

The three repositories used in the table above are public and unchanged, if they are useful for reproducing:

  • thankywal/muxel-probe-a — the byte-exact tree that imported successfully on 11 Aug
  • thankywal/muxel-probe-c — same tree with the deploy script removed
  • thankywal/muxel — the application itself

Happy to supply HAR files, the failing request payloads, or account IDs privately if that would help.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions