Repository navigation
Fix ISR routes using undocumented $0 token in Vercel route dest fields - #18044
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: c5e9f64 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
1 task
…writes Replace the undocumented `$0` capture reference in ISR route `dest` with `$1` by wrapping each ISR route's `src` regex in an outer capture group. Also validate that the path override starts with `/` in the entrypoint as defense in depth against substitution failures. Closes #18028
The startsWith('/') guard ignored a malformed trusted override and fell
through to the internal /_isr pathname. With a server catch-all
([...slug].astro), /_isr is a valid page, so a failing $1/$0 substitution
rendered 200 instead of failing. Return an explicit 404 before app.match()
when a trusted override channel (valid middleware secret or path token)
carries a missing or non-absolute path. Untrusted requests keep the existing
ignore-override behavior.
Also covers the improvement in test coverage:
- catch-all fixture: trusted overrides $0, $1, relative, and empty all
return 404 with no Location header and render no catch-all page; a valid
override still renders 200; an override with no path at all returns 404
- isr fixture: guard test now covers $0/relative/empty and asserts no
Location header; table-driven RegExp.exec() over emitted patterns proves
group 1 is the full pathname (static, dynamic, 404)
- spread fixture: group-1 exec assertions for root and spread patterns
matthewp
force-pushed
the
factory/fix-18028
branch
from
September 17, 2026 14:27
440a893 to
c5e9f64
Compare
|
|
The previous wording described the internal mechanism (capture group references, $1, the entrypoint, /_isr). Per the changeset guidelines, a patch changeset should state the user-facing effect.
matthewp
approved these changes
Sep 17, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changes
$0with$1in ISR routedestfields by wrapping each route'ssrcregex in an outer capture group (e.g.^/foo/?$→^(/foo/?)$).$0is excluded from Vercel's documented substitution character class ([1-9a-zA-Z]); when the production proxy intermittently failed to substitute it, the literal string"$0"was silently accepted by the entrypoint, resolved to pathname/$0, and — withtrailingSlash: 'always'— emitted a cacheable301redirect that poisoned the ISR cache for the full expiration window.realPath.startsWith('/')guard in the entrypoint as defense in depth. Any future substitution failure now results in the request falling through to the/_isrdefault instead of silently rendering a nonsense path.Testing
packages/integrations/vercel/test/isr.test.ts:'uses $1 (not $0) in ISR route dest'verifies the generatedconfig.jsonno longer contains$0;'ignores x_astro_path that does not start with /'covers the entrypoint guard for un-substituted path values.Docs
Closes #18028