Skip to content

Legacy /announcements/* redirects fail due to operator precedence bug in edge function #482

Description

@PedroAntunesCosta

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

  1. Request https://help.vtex.com/announcements/new-master-data-api-improves-setup-flexibility (or any legacy announcement path present in public/redirects.json).
  2. 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-480findAnnouncementSlug, 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions