cloudflare / cloudflare/workers-sdk

_redirects: dynamic-rule overflow silently drops rest of file; static/dynamic classification is order-dependent and unsurfaced

Open
#14,694 2 comments 0 reactions 0 assignees View on GitHub
feature:workers-assets package:workers-shared product:pages
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
186

Description

## Which Cloudflare product(s) does this pertain to?

Workers, Pages (static assets `_redirects` handling in `packages/workers-shared`)

## What is the issue or request?

The `_redirects` parser silently drops the remainder of a file once the dynamic-rule budget is exceeded, and the static/dynamic classification depends on rule ordering in a way that is not surfaced to the user at build or deploy time.

In [`parseRedirects.ts`](https://github.com/cloudflare/workers-sdk/blob/main/packages/workers-shared/utils/configuration/parseRedirects.ts):

- `canCreateStaticRule` starts `true` and is set to `false` permanently the first time a rule containing a splat (`*`) or placeholder (`:name`) is encountered.
- After that point, every subsequent rule — including exact-path rules that would otherwise be static — is counted against the 100 dynamic-rule budget.
- When `dynamicRules > maxDynamicRules` (100), the parser `break`s and skips all remaining lines, including any catch-all at the end of the file. The `invalid` entry records this, but nothing surfaces it to the user during `wrangler deploy`.

The documented limit of "2,000 static + 100 dynamic" is therefore only achievable if the entire file is ordered static-first. A single dynamic rule placed early collapses the effective static budget, and a file with more than 100 rules after the first dynamic rule loses its tail with no visible error.

This was reported publicly here: https://x.com/samuelcolvin/status/2076993431818084700 — a large `_redirects` file 404'd everything after the point where the dynamic budget overflowed, including the catch-all, with no build-time signal.

## Requested changes

Two options, not mutually exclusive:

1. **Non-breaking: surface a warning at build/deploy time.** Emit a warning from `wrangler deploy` (and `wrangler dev`) when:
- the dynamic-rule limit is exceeded and lines are skipped, or
- static rules appear after a dynamic rule (so they are being counted as dynamic).

The `invalid` messages already contain this information; they just are not surfaced. This changes no runtime behaviour.

2. **Behavioural fix, gated behind a compatibility date / `redirects.version`.** Classify rules by their own shape (splat/placeholder → dynamic, otherwise static) regardless of position, so exact-path rules after a dynamic rule are counted and matched as static.

This is a breaking change and should not apply to already-deployed configs:
- Previously-dropped rules would start firing.
- Precedence would change: `staticRedirectsMatcher` (exact-map) is evaluated before `generateRedirectsMatcher` (ordered regex) in [`rules-engine.ts`](https://github.com/cloudflare/workers-sdk/blob/main/packages/workers-shared/asset-worker/src/utils/rules-engine.ts), so reclassifying an exact-path rule that currently sits after a splat would move it ahead of that splat and can change which redirect wins for overlapping paths — even in files that never approach the limit.

The existing `redirects.version` gate in `generateRedirectsMatcher` and/or a compatibility date would let new deployments opt into the new semantics while existing deployments keep current behaviour.

## Docs

The current behaviour is being documented in cloudflare-docs (the `_redirects` "Per file" section) so that the ordering requirement and the silent-drop behaviour are explicit in the meantime: https://github.com/cloudflare/cloudflare-docs/pull/32083

Contributor guide

Open the contributing guide

Research direction

Start in packages/workers-shared/utils/configuration/parseRedirects.ts and trace how invalid entries are produced when the dynamic-rule limit is exceeded. Then read packages/workers-shared/asset-worker/src/utils/rules-engine.ts and the Wrangler deploy/dev paths to see how diagnostics and redirects.version are handled. Done means the agreed warning or compatibility-gated classification behavior is covered without changing unintended existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.