cloudflare / cloudflare/workers-sdk

Email Routing addresses: ["*@subdomain"] fails with code 2062 despite subdomain being enabled

Open
#15,521 1 comment 0 reactions 0 assignees View on GitHub
package:wrangler product:email
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
186

Description

### What versions & operating system are you using?

Paths containing my local username have been redacted.

```text
System:
OS: Linux 6.6 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat)
CPU: (24) x64 AMD Ryzen AI 9 HX 370 w/ Radeon 890M
Memory: 10.49 GB / 15.18 GB
Container: Yes
Shell: 5.2.21 - /bin/bash

Binaries:
Node: 24.19.0 - /home//.nvm/versions/node/v24.19.0/bin/node
npm: 11.17.0 - /home//.nvm/versions/node/v24.19.0/bin/npm
pnpm: 11.21.0 - /home//.local/share/pnpm/bin/pnpm

npmPackages:
wrangler: ^4.129.0 => 4.129.0
```

### Please provide a link to a minimal reproduction

N/A — this requires an Email Routing-enabled subdomain on a Cloudflare account, so I don't have a self-contained public repository that can reproduce it without account-side setup. The minimal `wrangler.jsonc` configuration and exact reproduction steps are included in the bug description below.

### Describe the Bug

I have an Email Routing subdomain that has already been successfully enabled in the Cloudflare dashboard.

I use `agent.asyncat.app` below as a redacted stand-in for the actual enabled subdomain.

A literal email address on that subdomain works correctly with Wrangler's `addresses` configuration:

```jsonc
{
"addresses": [
"ai@agent.asyncat.app"
]
}
```

`wrangler deploy` succeeds with this configuration.

However, changing the same enabled Email Routing subdomain to a catch-all:

```jsonc
{
"addresses": [
"*@agent.asyncat.app"
]
}
```

causes `wrangler deploy` to fail with error code `2062`:

```
✘ [ERROR] A request to the Cloudflare API (/accounts//email/routing/rules/plan) failed.

Unknown Email Routing domain: No Email Routing domain found for *@agent.asyncat.app [code: 2062]
Unknown Email Routing domain: No Email Routing domain found for *@agent.asyncat.app
```

### Minimal reproduction

Given an already-enabled Email Routing subdomain such as:

```text
agent.asyncat.app
```

use a `wrangler.jsonc` containing:

```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "",
"main": "src/index.ts",
"compatibility_date": "2026-09-03",

"addresses": [
"*@agent.asyncat.app"
]
}
```

Then run:

```bash
wrangler deploy
```

### Actual behavior

The Worker itself uploads and deploys, but configuring the Email Routing rules subsequently fails:

```text
⛅️ wrangler 4.129.0
────────────────────

Uploaded
Deployed triggers

✘ [ERROR] A request to the Cloudflare API
(/accounts//email/routing/rules/plan) failed.

Unknown Email Routing domain:
No Email Routing domain found for *@agent.asyncat.app [code: 2062]

Unknown Email Routing domain:
No Email Routing domain found for *@agent.asyncat.app
```

If I replace the catch-all with a literal address on exactly the same enabled Email Routing subdomain:

```jsonc
{
"addresses": [
"ai@agent.asyncat.app"
]
}
```

the deployment succeeds.

This appears to confirm that the Email Routing subdomain itself is correctly enabled and recognized. The failure seems specific to catch-all routing.

### Dashboard behavior

The Workers dashboard appears to expose the same distinction.

When creating an Email trigger for a specific address, the enabled Email Routing subdomain is available, and I can successfully configure an address such as:

```text
ai@agent.asyncat.app
```

However, after selecting:

> Match every address on the domain

the domain selector only shows apex/zone domains. The enabled Email Routing subdomain is no longer available.

The dashboard also displays:

> A domain can have one catch-all rule. It handles mail sent to any address no other rule matches.

This makes me wonder whether Email Routing catch-all rules are intentionally limited to apex/zone domains, while literal routing rules are supported on enabled subdomains.

### Expected behavior / clarification requested

The current Wrangler configuration schema describes `addresses` entries as either literal recipient addresses or `*@domain` catch-all addresses, with examples such as:

```text
support@asyncat.app
*@asyncat.app
```

As far as I can tell, the schema does not indicate that the domain in `*@domain` must specifically be an apex/zone domain, or that an enabled Email Routing subdomain cannot have its own catch-all rule.

Cloudflare's Email Routing documentation also describes enabling Email Routing on subdomains and creating routing rules on those subdomains, so this catch-all-specific distinction is not obvious from the current documentation or Wrangler schema.

Could you clarify which behavior is intended?

#### If catch-all routing should work on enabled Email Routing subdomains

Then:

```jsonc
{
"addresses": [
"*@agent.asyncat.app"
]
}
```

appears to expose a bug in the Email Routing planning/deployment flow.

#### If catch-all routing is intentionally limited to apex/zone domains

It would be helpful if the Wrangler config schema and Email Routing documentation explicitly documented this restriction.

It may also be useful for Wrangler to validate this case locally and return a clearer error, rather than accepting the configuration and failing later during the `/email/routing/rules/plan` API call.

### Why this was confusing

These two configurations appear equally valid from the current Wrangler schema:

```jsonc
"addresses": ["ai@agent.asyncat.app"]
```

and:

```jsonc
"addresses": ["*@agent.asyncat.app"]
```

but only the literal address works.

Since the first configuration succeeds on the same enabled Email Routing subdomain, the failure does not appear to be caused by subdomain onboarding itself.

It appears specific to catch-all routing.

Happy to provide additional logs or test other configurations if useful.

### Please provide any relevant error logs

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with the Wrangler configuration schema and the address-handling path for the `/email/routing/rules/plan` request. Reproduce the deployment using the provided `wrangler.jsonc`, comparing the literal and catch-all addresses on the same enabled subdomain. Done means confirming whether the API or Wrangler rejects subdomain catch-alls, then documenting or validating the intended behavior with an appropriate test.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
api, cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.