Skip to content

RedirectsProxy fails to match valid anchored regex redirect patterns returned by GraphQL, such as ^/cmmc$ #446

@RobertoArmas

Description

@RobertoArmas

Describe the Bug

We found an issue in RedirectsProxy.getExistsRedirect() where valid regex redirect patterns returned by the redirects GraphQL query are not matched correctly.

In our case, the redirect rule is present in the GraphQL response, but the proxy still logs skipped (redirect does not exist) and no redirect is applied.

Based on Sitecore documentation, this appears to be a valid configuration rather than a misuse of the feature. Sitecore documents that redirect patterns are treated as regular expressions when they start with ^ and end with $, and provides examples such as ^/blogs/blogs-november/$ and ^/ab[cd]/$. The same documentation also states that matching is case-insensitive and that patterns must begin with /.

Observed behavior
A redirect is successfully returned by the GraphQL response:

{
  "pattern": "^/cmmc$",
  "target": "/insights/cmmc-readiness-assessment#assessment",
  "redirectType": "REDIRECT_301",
  "isQueryStringPreserved": true,
  "isLanguagePreserved": false,
  "locale": ""
}

The incoming request is:

/cmmc

The proxy logs show that redirect data is fetched correctly, but the redirect is not matched:

content-sdk:redirects redirects proxy start: { pathname: '/cmmc', language: 'en', hostname: 'localhost:3000' }
content-sdk:redirects request: ...
content-sdk:redirects response in ...ms: { site: { siteInfo: { redirects: [Array] } } }
content-sdk:redirects skipped (redirect does not exist)

Why this looks like an SDK bug
According to the documentation, regex redirect patterns such as ^/blogs/blogs-november/$ and ^/ab[cd]/$ are valid supported scenarios. The pattern ^/cmmc$ follows the same documented format, so it should be considered a valid redirect rule.

However, in RedirectsProxy.getExistsRedirect(), the regex normalization logic appears to modify the incoming pattern before matching. In particular, the code prepends ^ before additional normalization:

redirect.pattern = escapeNonSpecialQuestionMarks(
  '^' + redirect.pattern.replace(new RegExp(`^[^]?/${locale}/`, 'gi'), '')
);

If the original pattern is already anchored, for example:

^/cmmc$

this can produce:

^^/cmmc$

Later cleanup logic appears to assume a cleaner input shape and may not fully normalize this case correctly:

redirect.pattern = `/^\/${redirect.pattern
  .replace(/^\/|\/$/g, '')
  .replace(/^\^\/|\/\$$/g, '')
  .replace(/^\^|\$$/g, '')
  .replace(/\$\/gi$/g, '')}[\/]?$/i`;

As a result, the final regex used for matching may no longer represent the original valid pattern, causing getExistsRedirect() to return undefined.

To Reproduce

  1. Configure a redirect rule that is returned by the redirects GraphQL query with:
  • pattern: ^/cmmc$
  • target: /insights/cmmc-readiness-assessment#assessment
  • redirectType: REDIRECT_301
  • isQueryStringPreserved: true
  • isLanguagePreserved: false
  1. Send a request to:
    /cmmc
  2. Observe that:
    the redirect is present in the GraphQL response
    the proxy logs skipped (redirect does not exist)
    no redirect response is generated

Expected Behavior

The redirect rule with pattern ^/cmmc$ should match the incoming request /cmmc and return a 301 redirect to:

/insights/cmmc-readiness-assessment#assessment

This expectation is consistent with the documented regex redirect behavior in Sitecore, where patterns starting with ^ and ending with $ are valid regex rules.

Possible Fix

It looks like the regex normalization logic should avoid blindly prepending ^ when the pattern is already anchored, or otherwise make the downstream normalization robust enough to preserve already valid regex patterns returned by user/graphql.

Provide environment information

  • Sitecore Version: Sitecore AI
  • Content SDK Version: 2.0.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    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