amruthpillai/reactive-resume · error · Error
Selector cannot end with a combinator.
Error message
Selector cannot end with a combinator.
What it means
Thrown by compileComplex after iterating a Selector AST when the loop produced at least one compound (so combinators were seen) but no trailing simple selectors remain. This means the parsed selector ends with a combinator token, e.g. 'div >' or 'a +'. A trailing combinator is syntactically invalid as a complete selector and would leave an empty final compound, so the compiler rejects it rather than emit an incomplete matcher. The error is only raised when compounds.length > 0 (at least one combinator existed) AND the trailing selectors buffer is empty.
Source
Thrown at packages/resume/src/stylesheet/selector.ts:263
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);
if (selectors.length === 0 || selectors.length > SEMANTIC_CSS_LIMITS_V1.maxSelectorsPerRule) {
throw new Error("Selector list has an unsupported number of selectors.");
}
return selectors.map((selector) => compileComplex(selector, context));
}
export function compileSelector(source: string | CssNode): CompileSelectorResult {
try {
const text = typeof source === "string" ? source : csstree.generate(source);View on GitHub (pinned to 3a5b12e2a4)
Solutions
- Inspect the offending selector and remove or complete the trailing combinator (e.g. change 'section >' to 'section > item').
- If the selector is built by concatenation, guard each segment so a combinator is only appended when a following compound is guaranteed — build segments as compound+cominator pairs.
- Validate selector strings with compileSelector() and surface the returned error field to the user at authoring time rather than at render time.
Example fix
// before
const source = 'section >';
const { selector, error } = compileSelector(source);
// selector === null, error === 'Selector cannot end with a combinator.'
// after
const source = 'section > item';
const { selector, error } = compileSelector(source);
// selector !== null, error === undefined Defensive patterns
Strategy: validation
Validate before calling
function endsWithCombinator(source: string): boolean {
return /[ >+~]\s*$/.test(source.trim());
}
if (endsWithCombinator(source)) {
// strip the trailing combinator or append the missing compound
} Type guard
function isValidSelector(source: string): boolean {
return !endsWithCombinator(source);
} Try / catch
const { selector, error } = compileSelector(source);
if (!selector && error === 'Selector cannot end with a combinator.') {
// prompt user to complete the selector
} Prevention
- When building selectors by concatenation, never append a combinator without a guaranteed following compound.
- Validate with compileSelector before persisting the stylesheet.
- Trim trailing whitespace and re-check after every edit.
When it happens
Trigger: Author input that ends in a combinator with nothing after it: 'section >', 'item +', 'group ~', or 'a b >'. Also triggered by selectors with stray trailing whitespace after an explicit combinator where css-tree emits a Combinator node as the last child. Template/string interpolation bugs that concatenate a selector prefix with an empty suffix can produce this (e.g. ``${base} >`` when base is the only content).
Common situations: Hand-editing a semantic stylesheet and leaving a dangling combinator. Programmatic selector assembly where a conditional segment is omitted, leaving a trailing combinator. Copy-paste from a larger rule that lost its final compound. Whitespace-only content accidentally parsed after an explicit combinator.
Related errors
- A compound selector can contain only one type selector.
- Selector has too many combinators.
- Selector list has an unsupported number of selectors.
- Selector is too long.
- Selector name is missing.
AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12).
Data as JSON: /api/errors/eb0a6482055071d7.
Report an issue: GitHub.