amruthpillai/reactive-resume · error · Error
Selector function nesting is too deep.
Error message
Selector function nesting is too deep.
What it means
Thrown by compileSimple for :is, :where, or :not when the recursive compile depth has reached SEMANTIC_CSS_LIMITS_V1.maxFunctionDepth (16). Each nested functional pseudo-class increments depth, preventing exponentially nested selectors.
Source
Thrown at packages/resume/src/stylesheet/selector.ts:211
if (matcher !== null && matcher !== undefined && !["=", "~=", "|=", "^=", "$=", "*="].includes(matcher)) {
throw new Error(`Unsupported attribute matcher ${matcher}.`);
}
const value = attributeValue(node);
if ((matcher === null || matcher === undefined) !== (value === null)) {
throw new Error("Attribute selector matcher and value must be used together.");
}
return { type: "attribute", name, matcher: matcher ?? null, value };
}
case "PseudoClassSelector": {
const name = astName(node);
if (["root", "first-child", "last-child", "only-child"].includes(name)) {
if (node.children !== null && node.children !== undefined)
throw new Error(`:${name} does not accept arguments.`);
return { type: "pseudo", name: name as "root" | "first-child" | "last-child" | "only-child" };
}
if (["is", "where", "not"].includes(name)) {
if (context.depth >= SEMANTIC_CSS_LIMITS_V1.maxFunctionDepth) {
throw new Error("Selector function nesting is too deep.");
}
const nested = childrenOf(node);
if (nested.length !== 1 || nested[0]?.type !== "SelectorList") {
throw new Error(`:${name} requires a selector list.`);
}
const selectors = compileSelectorList(nested[0], { depth: context.depth + 1 });
return { type: "pseudo", name: name as "is" | "where" | "not", selectors };
}
if (name === "nth-child" || name === "nth-of-type") {
if (context.depth >= SEMANTIC_CSS_LIMITS_V1.maxFunctionDepth) {
throw new Error("Selector function nesting is too deep.");
}
return compileNth(node, name, context);
}
throw new Error(`Unsupported pseudo-class :${name}.`);
}
case "ClassSelector":
throw new Error("Custom class selectors are not supported.");View on GitHub (pinned to 3a5b12e2a4)
Solutions
- Flatten the nesting: combine arguments into a single :is(a, b, c) instead of :is(:is(:is(a))).
- Cap generator recursion at maxFunctionDepth (16) before emitting.
- Hoist repeated sub-selectors into a comma-separated selector list.
Example fix
// before :is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(:is(section)))))))))))))))))) // after :is(section, item, field)
Defensive patterns
Strategy: validation
Validate before calling
import { SEMANTIC_CSS_LIMITS_V1 } from '@reactive-resume/resume';
const maxDepth = SEMANTIC_CSS_LIMITS_V1.maxFunctionDepth; // 16
const countFunctionDepth = (s) => (s.match(/:(is|where|not)\(/gi) || []).length;
const withinDepth = (s) => countFunctionDepth(s) <= maxDepth;
// verify before compiling deeply generated selectors Type guard
const isRejected = (r) => r.selector === null && typeof r.error === 'string';
Try / catch
const result = compileSelector(selector);
if (result.selector === null && result.error === 'Selector function nesting is too deep.') {
flattenIsWhereNot(selector);
} Prevention
- Flatten :is(:is(:is(...))) into :is(a, b, c).
- Cap generator recursion at maxFunctionDepth (16).
- Prefer comma-separated selector lists over nested functional wrappers.
When it happens
Trigger: Nesting :is/:where/:not more than 16 levels deep, e.g. :is(:is(:is(... 17 times ...))). Dynamically generated selectors that recurse without a depth bound.
Common situations: Programmatic selector generation that wraps each clause in :is; machine-generated CSS from a builder UI; unbounded recursion in a templating layer.
Related errors
- :${name} requires one An+B expression.
- Unsupported :${name} expression.
- Invalid :${name} expression.
- :nth-of-type does not accept an of selector.
- :${name} does not accept arguments.
AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12).
Data as JSON: /api/errors/1254ed55497bae4b.
Report an issue: GitHub.