What versions & operating system are you using?
- Wrangler 4.81.0 (deployed via
cloudflare/wrangler-action@v3.14.1, also reproduced locally)
- Linux Ubuntu 24.04 on
ubuntu-latest runners; Linux 6.8 locally
cloudflare/wrangler-action pinned at da0e0dfe58b7a431659754fdf3f186c529afbe65
Please provide a link to a minimal reproduction
Reproduction is on the live agentnative-site and agentnative-site-staging Workers on Cloudflare account 6c1bafea907fecbd4ad665b8d0a78e53 in the brettdavies/agentnative-site repo. A self-contained external repro can be built on request.
Describe the Bug
Summary
When the top-level Wrangler config declares a routes array containing a custom domain, and an env.<name> block does not override routes, the custom domain gets silently attached to BOTH Workers because routes is an inheritable key. Every wrangler deploy --env <name> re-asserts the inherited custom domain on the env Worker, which steals it away from the top-level Worker on every deploy.
This is documented behavior per the Inheritable keys list (and the contrast with the legacy v1 docs, which explicitly listed routes as not-inherited, makes the change easy to miss when porting older configs forward). The deploy log is the only practical signal that the inheritance has fired, and that signal arrives after the binding has already moved.
Setup that triggers it
Observed sequence
wrangler deploy (top-level): attaches anc.dev to agentnative-site. Log shows Deployed agentnative-site triggers ... anc.dev (custom domain).
wrangler deploy --env staging: attaches anc.dev to agentnative-site-staging. Log shows Deployed agentnative-site-staging triggers ... anc.dev (custom domain). The production binding is gone; the custom-domain record id is reassigned to the staging Worker.
- Any subsequent
wrangler deploy --env staging keeps anc.dev bound to staging.
- Any subsequent
wrangler deploy (top-level) flips it back.
This is the entire mechanism behind a "routing drift" bug we have been chasing for two weeks. It originally looked like a one-time manual misconfiguration during launch; in reality, every push to either branch was flipping the binding.
Why it surprised us
routes being inheritable interacts poorly with custom domains because the resulting CF resource is account-scoped, not Worker-scoped, and only one Worker can own a given custom-domain record. Other inheritable keys (assets, migrations, observability) are either no-ops to share or harmlessly redundant when inherited; routes for a custom domain is destructive when inherited because it transfers ownership.
The Wrangler deploy output does include the line Deployed <worker> triggers ... <hostname> (custom domain) on every deploy, but the framing reads as a normal "your Worker is live at these URLs" message, not as a "this attached the domain, possibly stealing it from another Worker" warning. The destination Worker doesn't have its own way to declare "I should NEVER own this domain"; the only way to break the inheritance is to set routes: [] (empty array) in the env block.
Custom-domain record ids appear to be deterministic
The custom-domain record id 8721a2ad00ee0c10c50d3357dba7b4e4efc7487a was assigned during the original v0.1 launch, then survived multiple delete+recreate cycles intact. After a DELETE on the record, a subsequent PUT of a new binding (different service, same hostname + zone_id) returned the same id back. This is undocumented, observed empirically. Useful context for anyone debugging "the record id matches what I had earlier but the binding is wrong" - the id is not stale, it's reusable.
What workarounds we ended up using
- Explicit empty override in the env block:
"routes": []. This breaks the inheritance and the env Worker stops asserting anc.dev. Verified to work locally; pending live confirmation on next staging deploy.
- A
gh api ... -X DELETE followed by gh api ... -X PUT to manually move the binding back to production after each accidental rebind. Recovery-only, not a fix.
Suggested improvements
- Wrangler deploy-time warning when an env block silently inherits a
routes array that contains an entry where custom_domain: true. Something like "warning: env.staging inherits route anc.dev from the top-level config; the deploy will reassign this custom domain from agentnative-site to agentnative-site-staging. Set routes: [] (or an explicit list) in env.staging to override."
- Documentation callout under Inheritable keys and on the Environments page noting that inheriting
routes from a parent with custom domains will reassign the domain on each deploy.
- Document the deterministic record id behavior for
workers/domains (record id derived from (account_id, zone_id, hostname), recycled across delete/recreate cycles).
What this issue is NOT
This is being filed as a docs/UX bug, not a Wrangler defect. The behavior matches the documented inheritance semantics. The cost is that the documented behavior, in a common multi-env setup with a production custom domain, silently mis-routes production traffic to staging on every dev push.
Please provide any relevant error logs
No errors. The deploys succeed silently. The relevant log lines are the Deployed <worker> triggers sections in two staging deploy runs:
Both runs contain the line anc.dev (custom domain) under the Deployed agentnative-site-staging triggers heading. That single log line is the only deploy-time signal that ownership of anc.dev just transferred.
What versions & operating system are you using?
cloudflare/wrangler-action@v3.14.1, also reproduced locally)ubuntu-latestrunners; Linux 6.8 locallycloudflare/wrangler-actionpinned atda0e0dfe58b7a431659754fdf3f186c529afbe65Please provide a link to a minimal reproduction
Reproduction is on the live
agentnative-siteandagentnative-site-stagingWorkers on Cloudflare account6c1bafea907fecbd4ad665b8d0a78e53in thebrettdavies/agentnative-siterepo. A self-contained external repro can be built on request.Describe the Bug
Summary
When the top-level Wrangler config declares a
routesarray containing a custom domain, and anenv.<name>block does not overrideroutes, the custom domain gets silently attached to BOTH Workers becauseroutesis an inheritable key. Everywrangler deploy --env <name>re-asserts the inherited custom domain on the env Worker, which steals it away from the top-level Worker on every deploy.This is documented behavior per the Inheritable keys list (and the contrast with the legacy v1 docs, which explicitly listed
routesas not-inherited, makes the change easy to miss when porting older configs forward). The deploy log is the only practical signal that the inheritance has fired, and that signal arrives after the binding has already moved.Setup that triggers it
{ "name": "agentnative-site", "main": "src/worker/index.ts", "compatibility_date": "2026-04-01", "routes": [{ "pattern": "anc.dev", "custom_domain": true }], "workers_dev": false, "env": { "staging": { "name": "agentnative-site-staging", "workers_dev": true // No `routes` field here. Looks like "staging has no custom domain". // Actually inherits the top-level routes and re-attaches anc.dev // to the staging Worker on every `wrangler deploy --env staging`. } } }Observed sequence
wrangler deploy(top-level): attachesanc.devtoagentnative-site. Log showsDeployed agentnative-site triggers ... anc.dev (custom domain).wrangler deploy --env staging: attachesanc.devtoagentnative-site-staging. Log showsDeployed agentnative-site-staging triggers ... anc.dev (custom domain). The production binding is gone; the custom-domain record id is reassigned to the staging Worker.wrangler deploy --env stagingkeepsanc.devbound to staging.wrangler deploy(top-level) flips it back.This is the entire mechanism behind a "routing drift" bug we have been chasing for two weeks. It originally looked like a one-time manual misconfiguration during launch; in reality, every push to either branch was flipping the binding.
Why it surprised us
routesbeing inheritable interacts poorly with custom domains because the resulting CF resource is account-scoped, not Worker-scoped, and only one Worker can own a given custom-domain record. Other inheritable keys (assets,migrations,observability) are either no-ops to share or harmlessly redundant when inherited;routesfor a custom domain is destructive when inherited because it transfers ownership.The Wrangler deploy output does include the line
Deployed <worker> triggers ... <hostname> (custom domain)on every deploy, but the framing reads as a normal "your Worker is live at these URLs" message, not as a "this attached the domain, possibly stealing it from another Worker" warning. The destination Worker doesn't have its own way to declare "I should NEVER own this domain"; the only way to break the inheritance is to setroutes: [](empty array) in the env block.Custom-domain record ids appear to be deterministic
The custom-domain record id
8721a2ad00ee0c10c50d3357dba7b4e4efc7487awas assigned during the original v0.1 launch, then survived multiple delete+recreate cycles intact. After a DELETE on the record, a subsequent PUT of a new binding (differentservice, samehostname+zone_id) returned the same id back. This is undocumented, observed empirically. Useful context for anyone debugging "the record id matches what I had earlier but the binding is wrong" - the id is not stale, it's reusable.What workarounds we ended up using
"routes": []. This breaks the inheritance and the env Worker stops asserting anc.dev. Verified to work locally; pending live confirmation on next staging deploy.gh api ... -X DELETEfollowed bygh api ... -X PUTto manually move the binding back to production after each accidental rebind. Recovery-only, not a fix.Suggested improvements
routesarray that contains an entry wherecustom_domain: true. Something like "warning: env.staging inherits routeanc.devfrom the top-level config; the deploy will reassign this custom domain fromagentnative-sitetoagentnative-site-staging. Setroutes: [](or an explicit list) in env.staging to override."routesfrom a parent with custom domains will reassign the domain on each deploy.workers/domains(record id derived from(account_id, zone_id, hostname), recycled across delete/recreate cycles).What this issue is NOT
This is being filed as a docs/UX bug, not a Wrangler defect. The behavior matches the documented inheritance semantics. The cost is that the documented behavior, in a common multi-env setup with a production custom domain, silently mis-routes production traffic to staging on every dev push.
Please provide any relevant error logs
No errors. The deploys succeed silently. The relevant log lines are the
Deployed <worker> triggerssections in two staging deploy runs:Both runs contain the line
anc.dev (custom domain)under theDeployed agentnative-site-staging triggersheading. That single log line is the only deploy-time signal that ownership ofanc.devjust transferred.