{"record":{"id":"7201aa45420e156b","repo":"remix-run/remix","slug":"matcher-resource-limit-exceeded","errorCode":null,"errorMessage":"matcher resource limit exceeded","messagePattern":"matcher resource limit exceeded","errorType":"exception","errorClass":"MatcherResourceError","httpStatus":null,"severity":"error","filePath":"packages/route-pattern/src/lib/match/limits.ts","lineNumber":79,"sourceCode":"  budget.actual = actual\n}\n\nexport function resolveMatcherLimits(limits?: Partial<MatcherLimits>): MatcherLimits {\n  let result = { ...defaultMatcherLimits, ...limits }\n  for (let [limit, maximum] of Object.entries(result)) {\n    if (!Number.isSafeInteger(maximum) || maximum < 0) {\n      throw new RangeError(`${limit} must be a non-negative safe integer`)\n    }\n  }\n  return result\n}\n\nexport function checkMatcherLimit(\n  limit: keyof MatcherLimits,\n  maximum: number,\n  actual: number,\n): void {\n  if (actual > maximum) throw new MatcherResourceError({ limit, maximum, actual })\n}\n","sourceCodeStart":61,"sourceCodeEnd":81,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/route-pattern/src/lib/match/limits.ts#L61-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect error.limit / error.maximum / error.actual to see which resource blew up","Raise the specific limit via the limits option to a value your real patterns need","Split patterns across multiple matchers instead of one giant matcher","Simplify offending patterns (flatten needless nesting, shorten literals)"],"exampleFix":"// before\nlet matcher = new RoutePatternMatcher({ patterns, limits: { matchWork: 1000 } })\n\n// after\nlet matcher = new RoutePatternMatcher({ patterns, limits: { matchWork: 100_000 } })","handlingStrategy":"try-catch","validationCode":"// estimate before matching: count patterns and nesting depth, compare to limits\nlet depth = (source.match(/\\(/g) ?? []).length\nif (depth > limits.maxNestingDepth) throw new Error('pattern too nested')","typeGuard":"null","tryCatchPattern":"try { matcher.match(pathname) } catch (e) { if (e instanceof MatcherResourceError) { /* log e.limit, e.actual; raise limit or split patterns */ } }","preventionTips":["Load-test with your full production route set","Split giant route tables across matchers","Alert when actual usage approaches limits"],"tags":["route-pattern","matcher","limits","performance"],"backgroundTag":"resource-limit-exceeded","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}