Description
The Netlify edge function redirect-from-old-portal.js incorrectly treats most legacy /announcements/* URLs as already modern and skips the redirect, causing a 404 instead of forwarding the visitor to the correct article.
Steps to Reproduce
- Request
https://help.vtex.com/announcements/new-master-data-api-improves-setup-flexibility (or any legacy announcement path present in public/redirects.json).
- Observe the response.
Expected Behavior
A 308 redirect to the resolved destination (e.g., /en/announcements/2017-12-22-new-master-data-api-increases-configuration-flexibility).
Actual Behavior
A 404 Not Found response with no Location header. The Netlify-Vary header is present, confirming the edge function executed but fell through to context.next() without redirecting.
Root Cause
netlify/edge-functions/redirect-from-old-portal.js:202 contains:
if (type === 'announcements' && (slug.match(/^\d{4}-\d{2}-\d{2}-/)) || slug.match(/\d{4}/) || slug.match(/\d{4}-\w+/)) {
&& binds tighter than || in JavaScript, so the condition evaluates as (type === 'announcements' && dateAtStart) || hasAnyFourDigits || hasFourDigitsThenWord. Any slug containing four consecutive digits anywhere satisfies slug.match(/\d{4}/), regardless of type. The destination resolved from public/redirects.json for legacy announcements is itself date-prefixed (e.g., 2017-12-22-...), so this branch is entered on nearly every legacy announcement redirect, and the function returns context.next(). Because context.next() forwards the original, unmodified incoming request, the origin receives the legacy path and returns 404.
Investigation Notes
Related Files
netlify/edge-functions/redirect-from-old-portal.js:202 — the faulty condition.
netlify/edge-functions/redirect-from-old-portal.js:456-480 — findAnnouncementSlug, the navigation.json-based resolution this bug prevents from being reached in most cases.
public/redirects.json — the fromLegacySlugs category contains numerous /announcements/* entries affected by this defect.
Suggested Investigation Paths
- Correct the operator grouping, e.g.
type === 'announcements' && (slug.match(/^\d{4}-\d{2}-\d{2}-/) || slug.match(/\d{4}/) || slug.match(/\d{4}-\w+/)), after confirming the intended condition (the three sub-patterns are largely redundant with each other).
- Add a regression test covering a legacy
/announcements/* path whose resolved destination is date-prefixed.
- Audit whether the same
\d{4} check should also gate the faq/known-issues types, or whether it was only intended for announcements.
Additional Context
Discovered during manual verification of edge-function behavior on help.vtex.com while a Netlify Split Test was active (PR #456 / EDU-17906). The defect is independent of Split Testing and reproduces identically with edge functions fully enabled and no split test running.
Description
The Netlify edge function
redirect-from-old-portal.jsincorrectly treats most legacy/announcements/*URLs as already modern and skips the redirect, causing a 404 instead of forwarding the visitor to the correct article.Steps to Reproduce
https://help.vtex.com/announcements/new-master-data-api-improves-setup-flexibility(or any legacy announcement path present inpublic/redirects.json).Expected Behavior
A
308redirect to the resolved destination (e.g.,/en/announcements/2017-12-22-new-master-data-api-increases-configuration-flexibility).Actual Behavior
A
404 Not Foundresponse with noLocationheader. TheNetlify-Varyheader is present, confirming the edge function executed but fell through tocontext.next()without redirecting.Root Cause
netlify/edge-functions/redirect-from-old-portal.js:202contains:&&binds tighter than||in JavaScript, so the condition evaluates as(type === 'announcements' && dateAtStart) || hasAnyFourDigits || hasFourDigitsThenWord. Any slug containing four consecutive digits anywhere satisfiesslug.match(/\d{4}/), regardless oftype. The destination resolved frompublic/redirects.jsonfor legacy announcements is itself date-prefixed (e.g.,2017-12-22-...), so this branch is entered on nearly every legacy announcement redirect, and the function returnscontext.next(). Becausecontext.next()forwards the original, unmodified incoming request, the origin receives the legacy path and returns404.Investigation Notes
Related Files
netlify/edge-functions/redirect-from-old-portal.js:202— the faulty condition.netlify/edge-functions/redirect-from-old-portal.js:456-480—findAnnouncementSlug, thenavigation.json-based resolution this bug prevents from being reached in most cases.public/redirects.json— thefromLegacySlugscategory contains numerous/announcements/*entries affected by this defect.Suggested Investigation Paths
type === 'announcements' && (slug.match(/^\d{4}-\d{2}-\d{2}-/) || slug.match(/\d{4}/) || slug.match(/\d{4}-\w+/)), after confirming the intended condition (the three sub-patterns are largely redundant with each other)./announcements/*path whose resolved destination is date-prefixed.\d{4}check should also gate thefaq/known-issuestypes, or whether it was only intended forannouncements.Additional Context
Discovered during manual verification of edge-function behavior on
help.vtex.comwhile a Netlify Split Test was active (PR #456 / EDU-17906). The defect is independent of Split Testing and reproduces identically with edge functions fully enabled and no split test running.