zloirock/core-js · error · SyntaxError

Invalid capture group name

Error message

Invalid capture group name

What it means

The RegExp constructor polyfill supports named capture groups. When parsing a pattern containing a named group (?<name>...), it validates that the name is non-empty and not already used. A duplicate or empty name raises a SyntaxError at construction time, matching ES2018 spec validation performed natively by modern engines.

Source

Thrown at packages/core-js/modules/es.regexp.constructor.js:115

    } else if (chr === ']') {
      brackets = false;
    } else if (!brackets) switch (true) {
      case chr === '[':
        brackets = true;
        break;
      case chr === '(':
        result += chr;
        if (exec(IS_NCG, stringSlice(string, index + 1))) {
          index += 2;
          ncg = true;
          groupid++;
        } else if (charAt(string, index + 1) !== '?') {
          groupid++;
        }
        continue;
      case chr === '>' && ncg:
        if (groupname === '' || hasOwn(names, groupname)) {
          throw new SyntaxError('Invalid capture group name');
        }
        names[groupname] = true;
        named[named.length] = [groupname, groupid];
        ncg = false;
        groupname = '';
        continue;
    }
    if (ncg) groupname += chr;
    else result += chr;
  }
  // convert `\k<name>` backreferences to numbered backreferences
  for (var ni = 0; ni < named.length; ni++) {
    var backref = '\\k<' + named[ni][0] + '>';
    var numRef = '\\' + named[ni][1];
    while (stringIndexOf(result, backref) > -1) {
      result = replace(result, backref, numRef);
    }
  } return [result, named];

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Rename one of the duplicate capture groups so every (?<name>) in the pattern is unique.
  2. Check for empty or malformed names: use only IdentifierPart chars and ensure a name follows '?<'.
  3. If merging patterns, wrap fragments in non-capturing groups and rename colliding groups programmatically.
  4. Test on the target environment — on modern engines the native RegExp throws the same class of SyntaxError earlier, so fix the pattern at the source.

Example fix

// before
const re = new RegExp('(?<year>\\d{4})-(?<year>\\d{2})'); // SyntaxError
// after
const re = new RegExp('(?<year>\\d{4})-(?<month>\\d{2})');
Defensive patterns

Strategy: validation

Validate before calling

function validateGroupNames(pattern) {
  const names = [...pattern.matchAll(/\(\?<([^>]+)>/g)].map(m => m[1]);
  const dup = names.filter((n, i) => names.indexOf(n) !== i);
  if (dup.length || names.some(n => !n)) throw new SyntaxError('Invalid capture group name in: ' + pattern);
}
validateGroupNames(pattern); const re = new RegExp(pattern);

Type guard

function hasUniqueNamedGroups(pattern) {
  const names = [...pattern.matchAll(/\(\?<([^>]+)>/g)].map(m => m[1]);
  return new Set(names).size === names.length && !names.includes('');
}
// usage: if (hasUniqueNamedGroups(pattern)) new RegExp(pattern);

Try / catch

let re;
try {
  re = new RegExp(pattern);
} catch (e) {
  if (e instanceof SyntaxError && /capture group/.test(e.message)) {
    // fall back to unnamed groups or log pattern for manual fix
  } else throw e;
}

Prevention

When it happens

Trigger: new RegExp('(?<a>x)(?<a>y)', flags) — duplicate group name; pattern like '(?<x>...)' where the polyfill's manual scan ends with an empty groupname; duplicate names across alternations '(?<year>\d{4})|(?<year>\d{2})'; running the same pattern twice after concatenating fragments that each declare the same name.

Common situations: Building regexes dynamically by concatenating pattern fragments that share group names; porting regexes from other languages (PCRE allows duplicate names with different backrefs); polyfilled environments (older browsers/Node) where native RegExp would have rejected earlier with a slightly different message; copy-pasting two regexes and merging their named groups.

Related errors


AI-assisted analysis of zloirock/core-js@84e45fba09 (2026-08-30). Data as JSON: /api/errors/71954df826628fd0. Report an issue: GitHub.