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
- 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)
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
- Load-test with your full production route set
- Split giant route tables across matchers
- Alert when actual usage approaches limits
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
- ${limit} must be a non-negative safe integer
- Expected at most ${maxTransforms} request transforms
- Exceeded maximum header size
- Exceeded maximum number of parts
- missing-hostname
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/7201aa45420e156b.
Report an issue: GitHub.