amruthpillai/reactive-resume · error · Error
Selector has too many combinators.
Error message
Selector has too many combinators.
What it means
Thrown by the semantic CSS compiler when a single complex selector chain accumulates more combinators than the V1 limit allows (SEMANTIC_CSS_LIMITS_V1.maxCombinatorsPerSelector = 16). The limit exists to bound compilation/matching cost in the restricted semantic stylesheet engine, which traverses a resume's semantic node tree. Combinators counted are descendant (' '), child ('>'), adjacent ('+'), and general-sibling ('~'). The check runs after each combinator is processed in compileComplex, so the error surfaces on the 17th combinator encountered.
Source
Thrown at packages/resume/src/stylesheet/selector.ts:254
function compileComplex(node: SelectorAst, context: CompileContext): CompiledComplexSelector {
if (node.type !== "Selector") throw new Error("Expected a Selector AST.");
const compounds: CompiledCompoundSelector[] = [];
const combinators: Combinator[] = [];
let selectors: CompiledSimpleSelector[] = [];
for (const child of childrenOf(node)) {
if (child.type === "Combinator") {
const name = astName(child) as Combinator;
if (![" ", ">", "+", "~"].includes(name) || selectors.length === 0) {
throw new Error("Unsupported or misplaced combinator.");
}
validateCompound(selectors);
compounds.push({ selectors });
selectors = [];
combinators.push(name);
if (combinators.length > SEMANTIC_CSS_LIMITS_V1.maxCombinatorsPerSelector) {
throw new Error("Selector has too many combinators.");
}
continue;
}
const selector = compileSimple(child, context);
if (selector) selectors.push(selector);
}
if (selectors.length === 0 && compounds.length > 0) throw new Error("Selector cannot end with a combinator.");
validateCompound(selectors);
compounds.push({ selectors });
const specificity = SpecificityCalculator.calculateForAST(node).toArray();
return { compounds, combinators, specificity: [specificity[0], specificity[1], specificity[2]] };
}
function compileSelectorList(node: SelectorAst, context: CompileContext): readonly CompiledComplexSelector[] {
if (node.type !== "SelectorList") throw new Error("Expected a SelectorList AST.");
const selectors = childrenOf(node);View on GitHub (pinned to 3a5b12e2a4)
Solutions
- Count the combinators in the offending selector; remove or collapse descendant chains so the total is 16 or fewer. Replace deep chains like 'resume page section group item' with a single attribute or role selector targeting the node directly (e.g. 'item[role="..."]').
- Split one oversized selector into multiple rules that each target shallower subtrees, letting the cascade combine them.
- Use :is() / :where() to group targets without adding top-level combinators — note that combinators inside :is/:where are compiled at depth+1 but do not inflate the outer combinator count.
- If the limit is genuinely too low for a legitimate use case, evaluate raising maxCombinatorsPerSelector in packages/resume/src/stylesheet/limits.ts, but treat this as a signal that the selector is over-specified.
Example fix
// before const source = 'resume page section group block item field label value text'; const result = compileSelector(source); // result.error === 'Selector has too many combinators.' // after: collapse to an attribute/role-targeted selector with far fewer combinators const source = 'item[label="name"] text'; const result = compileSelector(source);
Defensive patterns
Strategy: validation
Validate before calling
import { compileSelector } from '@reactive-resume/resume/stylesheet';
const MAX = 16; // SEMANTIC_CSS_LIMITS_V1.maxCombinatorsPerSelector
function countCombinators(source: string): number {
return (source.match(/[ >+~](?![^[]*\])/g) ?? []).length;
}
// before compile:
if (countCombinators(source) > MAX) {
// reject/repair the selector before calling compileSelector
} Type guard
function isWithinCombinatorLimit(source: string): boolean {
return countCombinators(source) <= 16;
} Try / catch
import { compileSelector } from '@reactive-resume/resume/stylesheet';
const { selector, error } = compileSelector(source);
if (!selector) {
// error === 'Selector has too many combinators.' etc.
reportToUser(error);
} Prevention
- Prefer attribute/role selectors over deep descendant chains.
- If generating CSS programmatically, count combinators before emitting a rule.
- Run compileSelector at authoring time and surface its error field to the user immediately.
When it happens
Trigger: Authoring a semantic CSS selector with an extremely deep element chain, e.g. 'resume page section group item field label value' (more than 16 descendant hops) or a long sibling chain 'a + b + c + ... + r'. Also triggered by machine-generated stylesheets that emit deeply nested combinators. The counter increments once per combinator node parsed by css-tree, so even seemingly short text with many implicit descendants ('a b c d ...') counts each space as one combinator.
Common situations: AI-generated or auto-generated semantic CSS that over-specifies element paths. Manually authored rules that try to reach deep into the resume semantic tree instead of using attribute/role selectors. Copying browser-targeted CSS into the semantic stylesheet (which is far more restrictive). Confusion about the difference between combinators (which count) and compound selectors (which do not).
Related errors
- Selector list has an unsupported number of selectors.
- Selector is too long.
- Selector cannot end with a combinator.
- Selector name is missing.
- Attribute value is missing.
AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12).
Data as JSON: /api/errors/a91aced267797229.
Report an issue: GitHub.