react-navigation/react-navigation · error

Encountered '(' without preceding ':' in path: ${path}

Error message

Encountered '(' without preceding ':' in path: ${path}

What it means

Parentheses in a path pattern are only meaningful as part of a param's regex constraint, e.g. ':id(\d+)'. A '(' that appears without a preceding ':param' has no valid interpretation, so pattern parsing fails. Thrown while normalizing the linking config's path strings.

Source

Thrown at packages/core/src/getPatternParts.tsx:52

    if (char === ':') {
      // The segment must start with a colon if it's a param
      if (current.segment === ':') {
        isParam = true;
      } else if (!isRegex) {
        throw new Error(
          `Encountered ':' in the middle of a segment in path: ${path}`
        );
      }
    } else if (char === '(' && !isEscaped && !isInCharClass) {
      if (isParam) {
        if (isRegex) {
          // The '(' is part of the regex if we're already inside one
          regexInnerParens++;
        } else {
          isRegex = true;
        }
      } else {
        throw new Error(
          `Encountered '(' without preceding ':' in path: ${path}`
        );
      }
    } else if (char === ')' && !isEscaped && !isInCharClass) {
      if (isParam && isRegex) {
        if (regexInnerParens) {
          // The ')' is part of the regex if we're already inside one
          regexInnerParens--;
        } else {
          current.pattern += char;
          isRegex = false;
          isParam = false;
        }
      } else {
        throw new Error(
          `Encountered ')' without preceding '(' in path: ${path}`
        );
      }

View on GitHub (pinned to ab1319d6bb)

Solutions

  1. Remove the bare parentheses or escape intent another way: 'pages/:id' instead of 'page(s)/:id'.
  2. For optional segments use the question-mark param syntax: 'detail/:id?' where supported.
  3. If a regex is intended, attach it to a param: ':type([a-z]+)' or ':id(\d+)'.
  4. Search linking config paths for /\(/ and fix each occurrence.

Example fix

// before
const config = { screens: { List: { path: 'page(s)/:id' } } };
// after
const config = { screens: { List: { path: 'pages/:id' } } };
// regex variant:
const config = { screens: { List: { path: 'list/:filter([a-z]+)' } } };
Defensive patterns

Strategy: validation

Validate before calling

function validateNoBareParens(p) {
  let open = 0, inParam = false;
  for (const ch of p) {
    if (ch === ':') inParam = true;
    if (ch === '/') inParam = false;
    if (ch === '(') { if (!inParam) throw new Error(`'(' without ':' in '${p}'`); open++; }
    if (ch === ')') open--;
  }
  return p;
}

Type guard

function parensOnlyAfterParam(p) {
  return !/[(]/.test(p.replace(/:[^/(]*\([^)]*\)/g, ''));
}

Try / catch

try {
  const parts = getPatternParts(path);
} catch (err) {
  if (err.message.includes("'(' without preceding ':'")) {
    console.error(`Remove or param-wrap '(' in: ${path}`);
  } else throw err;
}

Prevention

When it happens

Trigger: A linking-config path containing a bare '(' such as 'page(s)/:id' or 'filter(:type)' — parentheses used as literal text or grouping without an associated param.

Common situations: Regex habits from other routers applied to plain path text; trying to make optional segments with parens like 'detail(/:id)' instead of the supported ':id?' syntax; leftover regex fragments from copy-paste.

Related errors


AI-assisted analysis of react-navigation/react-navigation@ab1319d6bb (2026-08-31). Data as JSON: /api/errors/96dfbcf3b875bb8a. Report an issue: GitHub.