What versions & operating system are you using?
- Wrangler 4.139.0 (the same code path is still present on
main at 087ea32; no related entry in the CHANGELOG up to 4.143.0)
- Node v24.21.0, macOS 27.0
- Deployments are created by Workers Builds (Git-connected Worker with Preview builds enabled) and by
wrangler preview from the CLI
Please provide a link to a minimal reproduction
N/A — any Worker whose Wrangler config has a previews block reproduces it with the steps below
Describe the Bug
Secrets set on a Worker Preview are dropped by the next wrangler preview deployment to that Preview. Each code deployment to the Preview (including those created by Workers Builds on push) ends up with no secrets, so a long-lived Preview (e.g. a staging Preview tracking a branch) silently loses its secrets on every push.
Steps to reproduce
- Create a Preview named
staging with wrangler preview --name staging (Worker config has a previews block).
- Set secrets on it:
wrangler preview secret put MY_SECRET --name staging
wrangler preview secret list --name staging # MY_SECRET is listed
- Deploy code to the same Preview again (either
wrangler preview --name staging, or push to the tracked branch so Workers Builds deploys it).
wrangler preview secret list --name staging → Secrets: (none). At runtime env.MY_SECRET is undefined.
We observed this with Workers Builds deployments: 9 secrets were set on the staging Preview, and after the next push the latest deployment listed no secrets and the Worker failed at runtime. We did not separately re-run step 3 with the CLI, but the CLI wrangler preview command goes through the same runPreview → assemblePreviewDeploymentSettings path.
Expected
Secrets set on a Preview persist across later code deployments to that Preview, the same way wrangler deploy / wrangler versions upload keep secrets from the previous version. The Previews configuration docs describe per-Preview secrets and say active Previews keep their secrets ("Later changes to Base secrets apply only to new Previews, so active Previews remain unchanged"), which implies the secrets live with the Preview rather than with a single deployment.
Actual
The deployment history of the Preview shows the secrets being set (one deployment per secret put), and then the next code deployment has no secrets at all. Preview base config secrets do not fill the gap either, because they are only applied when a Preview is created.
Likely cause
assemblePreviewDeploymentSettings in packages/deploy-helpers/src/preview/preview.ts builds the deployment env only from the config bindings (extractConfigBindings(config)), --var values and --secrets-file values. It does not add { type: "inherit" } bindings for existing secrets, unlike the regular upload path, which passes keepSecrets: true ("inherit all unchanged secrets from the previous Worker Version") and, for secrets.required, adds inherit bindings via addRequiredSecretsInheritBindings. If the Preview deployments API is expected to merge secrets from the previous deployment on its own, then the bug is on the API side instead. Either way, the observed behaviour is that secrets are lost.
Also affects cf
cf previews deploy (cloudflare/cf) calls previewBuildOutput from @cloudflare/deploy-helpers, which goes through the same runPreview → assemblePreviewDeploymentSettings path. cf previews deploy has no --secrets-file equivalent, so the workaround below is not available there.
Workaround
Pass all secrets on every deployment with wrangler preview --secrets-file <file> (for Workers Builds, generate the file from build secrets in the preview command), or re-run wrangler preview secret bulk --name <preview> after each deployment.
Please provide any relevant error logs
No error is reported by Wrangler. The failure shows up only at runtime, when the Worker reads a missing secret.
What versions & operating system are you using?
mainat 087ea32; no related entry in the CHANGELOG up to 4.143.0)wrangler previewfrom the CLIPlease provide a link to a minimal reproduction
N/A — any Worker whose Wrangler config has a
previewsblock reproduces it with the steps belowDescribe the Bug
Secrets set on a Worker Preview are dropped by the next
wrangler previewdeployment to that Preview. Each code deployment to the Preview (including those created by Workers Builds on push) ends up with no secrets, so a long-lived Preview (e.g. astagingPreview tracking a branch) silently loses its secrets on every push.Steps to reproduce
stagingwithwrangler preview --name staging(Worker config has apreviewsblock).wrangler preview secret put MY_SECRET --name staging wrangler preview secret list --name staging # MY_SECRET is listedwrangler preview --name staging, or push to the tracked branch so Workers Builds deploys it).wrangler preview secret list --name staging→ Secrets: (none). At runtimeenv.MY_SECRETisundefined.We observed this with Workers Builds deployments: 9 secrets were set on the
stagingPreview, and after the next push the latest deployment listed no secrets and the Worker failed at runtime. We did not separately re-run step 3 with the CLI, but the CLIwrangler previewcommand goes through the samerunPreview→assemblePreviewDeploymentSettingspath.Expected
Secrets set on a Preview persist across later code deployments to that Preview, the same way
wrangler deploy/wrangler versions uploadkeep secrets from the previous version. The Previews configuration docs describe per-Preview secrets and say active Previews keep their secrets ("Later changes to Base secrets apply only to new Previews, so active Previews remain unchanged"), which implies the secrets live with the Preview rather than with a single deployment.Actual
The deployment history of the Preview shows the secrets being set (one deployment per
secret put), and then the next code deployment has no secrets at all. Preview base config secrets do not fill the gap either, because they are only applied when a Preview is created.Likely cause
assemblePreviewDeploymentSettingsinpackages/deploy-helpers/src/preview/preview.tsbuilds the deploymentenvonly from the config bindings (extractConfigBindings(config)),--varvalues and--secrets-filevalues. It does not add{ type: "inherit" }bindings for existing secrets, unlike the regular upload path, which passeskeepSecrets: true("inherit all unchanged secrets from the previous Worker Version") and, forsecrets.required, adds inherit bindings viaaddRequiredSecretsInheritBindings. If the Preview deployments API is expected to merge secrets from the previous deployment on its own, then the bug is on the API side instead. Either way, the observed behaviour is that secrets are lost.Also affects
cfcf previews deploy(cloudflare/cf) callspreviewBuildOutputfrom@cloudflare/deploy-helpers, which goes through the samerunPreview→assemblePreviewDeploymentSettingspath.cf previews deployhas no--secrets-fileequivalent, so the workaround below is not available there.Workaround
Pass all secrets on every deployment with
wrangler preview --secrets-file <file>(for Workers Builds, generate the file from build secrets in the preview command), or re-runwrangler preview secret bulk --name <preview>after each deployment.Please provide any relevant error logs
No error is reported by Wrangler. The failure shows up only at runtime, when the Worker reads a missing secret.