Skip to content

[wrangler] Fix deploy rejecting already-applied Durable Object migration histories - #15795

Open
SulimanAbdulrazzaq wants to merge 2 commits into
cloudflare:mainfrom
SulimanAbdulrazzaq:fix/do-migrations-replay-without-containers
Open

SulimanAbdulrazzaq wants to merge 2 commits into
cloudflare:mainfrom
SulimanAbdulrazzaq:fix/do-migrations-replay-without-containers

Conversation

@SulimanAbdulrazzaq

@SulimanAbdulrazzaq SulimanAbdulrazzaq commented Sep 23, 2026

Copy link
Copy Markdown

Fixes #15741.

wrangler deploy and wrangler versions upload, including --dry-run, reject a Worker whose migrations history has a later tag that deletes or renames a class that no earlier tag in the file creates, with Cannot apply deleted_classes migration to non-existent class <name> (or the renamed_classes equivalent).

Wrangler only uploads the migration steps after the Worker's current migration tag, so tags that were already applied are not sent again. Since #15480, both commands call prepareDurableObjectContainerApplications, which validates Durable Object-managed Containers through validateDurableObjectContainerApplications. That replays the whole migrations history from an empty state via getDurableObjectClassNameToUseSQLiteMap, and a run without --dry-run replays it a second time for the storage check. Both replays ran even when no containers were configured, so every Worker with such a history was affected.

This PR returns early from prepareDurableObjectContainerApplications when there are no Durable Object-managed Containers, the same way validateImageLessContainerApplicationsForUpload and deployDurableObjectContainerApplications already do. The replay now runs only for Workers that use those containers. It does not change how the replay treats unknown classes: wrangler dev and type generation call the same function, so relaxing it there is a separate decision.

wrangler deploy also replayed the history in getNormalizedContainerOptions for Workers with other Containers. It called validateDurableObjectContainerApplications even when no Durable Object-managed Containers were configured. It also replayed the history to find each container's class, even when a Durable Object binding already names that class. The validation now runs only when there are Durable Object-managed Containers, and the lookup replays the history only when no binding names the class. That lookup replay predates #15480.

Tests:

  • deploy-helpers: prepareDurableObjectContainerApplications resolves to {} for such a history when no Durable Object-managed Containers are configured, both with and without dryRun, and does not look up Durable Object namespaces.
  • wrangler: wrangler deploy of a Worker whose current migration tag is v2, where v2 deletes a class that v1 never created, succeeds and uploads no migrations.
  • wrangler: getNormalizedContainerOptions normalizes a Container bound to its Durable Object for such a history, and wrangler deploy --dry-run with a registry-image Container and such a history succeeds.

All four new tests fail on main with the error above and pass with this change.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: this is a bug fix that restores the previous deploy behaviour, with no new options or output.

Note

This is a contribution from an AI agent: Claude Code, Claude Opus 5 (implementation) and Claude Opus 5.5 (review).


Devin Review

…ion histories

`prepareDurableObjectContainerApplications` runs for every `wrangler deploy`
(unless `--containers-rollout=none`) and every `wrangler versions upload`. It
validated Durable Object-managed Containers by replaying the whole
`migrations` history from an empty state, even when no such containers were
configured. A history in which a later tag deletes or renames a class that no
earlier tag in the file creates then failed with an error such as "Cannot
apply deleted_classes migration to non-existent class", although only the
steps after the Worker's current migration tag are uploaded.

Return early when there are no Durable Object-managed Containers, as the
other container steps already do, so the replay only runs for Workers that
use them.

Fixes cloudflare#15741
@changeset-bot

changeset-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 328e455

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@cloudflare/deploy-helpers Patch
wrangler Patch
@cloudflare/remote-bindings Patch
@cloudflare/vite-plugin Patch
@cloudflare/vitest-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-project-automation github-project-automation Bot moved this to Untriaged in workers-sdk Sep 23, 2026
@workers-devprod
workers-devprod requested review from a team and cjol and removed request for a team September 23, 2026 00:24
@workers-devprod

workers-devprod commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/cloudchamber
  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/deploy-applied-migrations-without-containers.md: [@cloudflare/wrangler]
  • packages/deploy-helpers/src/deploy/helpers/durable-object-container-applications.ts: [@cloudflare/wrangler]
  • packages/deploy-helpers/tests/durable-object-container-applications.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/containers/config.test.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/wrangler/src/tests/containers/deploy.test.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]
  • packages/wrangler/src/tests/deploy/durable-objects.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/containers/config.ts: [@cloudflare/cloudchamber @cloudflare/wrangler]

devin-ai-integration[bot]

This comment was marked as resolved.

@pkg-pr-new

pkg-pr-new Bot commented Sep 23, 2026

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/@cloudflare/autoconfig@15795

@cloudflare/build-output-utils

npm i https://pkg.pr.new/@cloudflare/build-output-utils@15795

@cloudflare/codemods

npm i https://pkg.pr.new/@cloudflare/codemods@15795

@cloudflare/config

npm i https://pkg.pr.new/@cloudflare/config@15795

@cloudflare/containers-shared

npm i https://pkg.pr.new/@cloudflare/containers-shared@15795

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@15795

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/@cloudflare/deploy-helpers@15795

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@15795

miniflare

npm i https://pkg.pr.new/miniflare@15795

@cloudflare/pages-functions

npm i https://pkg.pr.new/@cloudflare/pages-functions@15795

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@15795

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@15795

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@15795

@cloudflare/vitest-plugin

npm i https://pkg.pr.new/@cloudflare/vitest-plugin@15795

@cloudflare/workers-auth

npm i https://pkg.pr.new/@cloudflare/workers-auth@15795

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@15795

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@15795

wrangler

npm i https://pkg.pr.new/wrangler@15795

commit: 328e455

…rable Object

`getNormalizedContainerOptions` runs on every `wrangler deploy` with
Containers configured. It still replayed the whole `migrations` history in
two places before the early return in
`prepareDurableObjectContainerApplications` could apply:

- `validateDurableObjectContainerApplications(config)` ran even when no
  Durable Object-managed Containers were configured;
- the class lookup for other Containers replayed the history even when a
  Durable Object binding already names the container's class.

An already-applied history that deletes or renames a class no earlier tag
creates therefore still blocked `wrangler deploy` for a Worker with a
standard Container. Validate Durable Object-managed Containers only when
there are some, and replay the history for other Containers only when no
binding names the class.
@workers-devprod
workers-devprod requested a review from a team September 23, 2026 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

wrangler deploy rejects an already-applied migration history: "Cannot apply deleted_classes migration to non-existent class" (regression in 4.131.0)

2 participants