{"record":{"id":"a91aced267797229","repo":"amruthpillai/reactive-resume","slug":"selector-has-too-many-combinators","errorCode":null,"errorMessage":"Selector has too many combinators.","messagePattern":"Selector has too many combinators\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/resume/src/stylesheet/selector.ts","lineNumber":254,"sourceCode":"\nfunction compileComplex(node: SelectorAst, context: CompileContext): CompiledComplexSelector {\n\tif (node.type !== \"Selector\") throw new Error(\"Expected a Selector AST.\");\n\n\tconst compounds: CompiledCompoundSelector[] = [];\n\tconst combinators: Combinator[] = [];\n\tlet selectors: CompiledSimpleSelector[] = [];\n\tfor (const child of childrenOf(node)) {\n\t\tif (child.type === \"Combinator\") {\n\t\t\tconst name = astName(child) as Combinator;\n\t\t\tif (![\" \", \">\", \"+\", \"~\"].includes(name) || selectors.length === 0) {\n\t\t\t\tthrow new Error(\"Unsupported or misplaced combinator.\");\n\t\t\t}\n\t\t\tvalidateCompound(selectors);\n\t\t\tcompounds.push({ selectors });\n\t\t\tselectors = [];\n\t\t\tcombinators.push(name);\n\t\t\tif (combinators.length > SEMANTIC_CSS_LIMITS_V1.maxCombinatorsPerSelector) {\n\t\t\t\tthrow new Error(\"Selector has too many combinators.\");\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst selector = compileSimple(child, context);\n\t\tif (selector) selectors.push(selector);\n\t}\n\n\tif (selectors.length === 0 && compounds.length > 0) throw new Error(\"Selector cannot end with a combinator.\");\n\tvalidateCompound(selectors);\n\tcompounds.push({ selectors });\n\tconst specificity = SpecificityCalculator.calculateForAST(node).toArray();\n\treturn { compounds, combinators, specificity: [specificity[0], specificity[1], specificity[2]] };\n}\n\nfunction compileSelectorList(node: SelectorAst, context: CompileContext): readonly CompiledComplexSelector[] {\n\tif (node.type !== \"SelectorList\") throw new Error(\"Expected a SelectorList AST.\");\n\tconst selectors = childrenOf(node);","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/resume/src/stylesheet/selector.ts#L236-L272","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nconst source = 'resume page section group block item field label value text';\nconst result = compileSelector(source);\n// result.error === 'Selector has too many combinators.'\n\n// after: collapse to an attribute/role-targeted selector with far fewer combinators\nconst source = 'item[label=\"name\"] text';\nconst result = compileSelector(source);","handlingStrategy":"validation","validationCode":"import { compileSelector } from '@reactive-resume/resume/stylesheet';\n\nconst MAX = 16; // SEMANTIC_CSS_LIMITS_V1.maxCombinatorsPerSelector\nfunction countCombinators(source: string): number {\n  return (source.match(/[ >+~](?![^[]*\\])/g) ?? []).length;\n}\n// before compile:\nif (countCombinators(source) > MAX) {\n  // reject/repair the selector before calling compileSelector\n}","typeGuard":"function isWithinCombinatorLimit(source: string): boolean {\n  return countCombinators(source) <= 16;\n}","tryCatchPattern":"import { compileSelector } from '@reactive-resume/resume/stylesheet';\nconst { selector, error } = compileSelector(source);\nif (!selector) {\n  // error === 'Selector has too many combinators.' etc.\n  reportToUser(error);\n}","preventionTips":["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."],"tags":["css","semantic-stylesheet","selector","limit"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}