remix-run/remix · error · MatcherResourceError

matcher resource limit exceeded

Error message

matcher resource limit exceeded

What it means

To keep pattern matching fast and safe, the matcher tracks resource usage (work steps, pattern sizes, nesting depth) against configured limits. When actual usage exceeds a limit, a MatcherResourceError is thrown identifying which limit, its maximum, and the actual count. This protects against pathological patterns causing catastrophic backtracking or memory blowups.

Source

Thrown at packages/route-pattern/src/lib/match/limits.ts:79

  budget.actual = actual
}

export function resolveMatcherLimits(limits?: Partial<MatcherLimits>): MatcherLimits {
  let result = { ...defaultMatcherLimits, ...limits }
  for (let [limit, maximum] of Object.entries(result)) {
    if (!Number.isSafeInteger(maximum) || maximum < 0) {
      throw new RangeError(`${limit} must be a non-negative safe integer`)
    }
  }
  return result
}

export function checkMatcherLimit(
  limit: keyof MatcherLimits,
  maximum: number,
  actual: number,
): void {
  if (actual > maximum) throw new MatcherResourceError({ limit, maximum, actual })
}

View on GitHub (pinned to 9696913134)

Solutions

  1. Inspect error.limit / error.maximum / error.actual to see which resource blew up
  2. Raise the specific limit via the limits option to a value your real patterns need
  3. Split patterns across multiple matchers instead of one giant matcher
  4. Simplify offending patterns (flatten needless nesting, shorten literals)

Example fix

// before
let matcher = new RoutePatternMatcher({ patterns, limits: { matchWork: 1000 } })

// after
let matcher = new RoutePatternMatcher({ patterns, limits: { matchWork: 100_000 } })
Defensive patterns

Strategy: try-catch

Validate before calling

// estimate before matching: count patterns and nesting depth, compare to limits
let depth = (source.match(/\(/g) ?? []).length
if (depth > limits.maxNestingDepth) throw new Error('pattern too nested')

Type guard

null

Try / catch

try { matcher.match(pathname) } catch (e) { if (e instanceof MatcherResourceError) { /* log e.limit, e.actual; raise limit or split patterns */ } }

Prevention

When it happens

Trigger: Matching or parsing a pattern/set of patterns large or deeply nested enough to exceed any configured limit — e.g. thousands of nested optional groups, extremely long patterns, or batching a huge number of patterns into one matcher with default limits.

Common situations: Auto-generated route patterns from a CMS or filesystem growing over time; deeply nested optionals from code generation; merging many apps' routes into a single matcher; someone lowered limits defensively and real traffic now trips them.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/7201aa45420e156b. Report an issue: GitHub.