amruthpillai/reactive-resume · error · Error
Unsupported attribute matcher ${matcher}.
Error message
Unsupported attribute matcher ${matcher}. What it means
Thrown by compileSimple in the AttributeSelector branch when node.matcher is present but is not one of the six supported CSS matchers '=', '~=', '|=', '^=', '$=', '*='. Any other matcher token is rejected.
Source
Thrown at packages/resume/src/stylesheet/selector.ts:194
}
function compileSimple(node: SelectorAst, context: CompileContext): CompiledSimpleSelector | null {
switch (node.type) {
case "TypeSelector": {
const name = astName(node);
if (name === "*") return { type: "universal" };
if (!knownKinds.has(name)) throw new Error(`Unknown semantic element ${name}.`);
return { type: "type", name: name as SemanticNode["kind"] };
}
case "IdSelector":
return { type: "id", value: astName(node) };
case "AttributeSelector": {
const name = astName(node);
if (!knownAttributes.has(name)) throw new Error(`Unknown semantic attribute ${name}.`);
if (node.flags) throw new Error("Attribute selector flags are not supported.");
const matcher = node.matcher as AttributeMatcher | null | undefined;
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.");
}View on GitHub (pinned to 3a5b12e2a4)
Solutions
- Use one of the six standard matchers: =, ~=, |=, ^=, $=, *=.
- Pass a selector string instead of a custom AST so css-tree only emits standard matchers.
- For presence tests, omit the matcher entirely: [type].
Example fix
// before // (custom AST with matcher '~=i') // after [type~='experience']
Defensive patterns
Strategy: validation
Validate before calling
const MATCHERS = new Set(['=', '~=', '|=', '^=', '$=', '*=']); const matcherIsSupported = (m) => m === null || m === undefined || MATCHERS.has(m); // verify any matcher before building an attribute selector AST
Type guard
const isRejected = (r) => r.selector === null && typeof r.error === 'string';
Try / catch
const result = compileSelector(selectorOrAst);
if (result.selector === null && result.error.startsWith('Unsupported attribute matcher ')) {
rewriteToStandardMatcher();
} Prevention
- Use only the six standard CSS attribute matchers.
- Pass selector strings rather than custom AST to avoid non-standard matcher tokens.
- For presence tests, omit the matcher entirely.
When it happens
Trigger: A programmatically built AST carrying an unsupported matcher string, or a css-tree version that emits a matcher token this compiler does not whitelist.
Common situations: Feeding a hand-constructed CssNode to compileSelector; upgrading css-tree; exotic/non-standard matcher syntax.
Related errors
- Attribute selector matcher and value must be used together.
- Attribute ${selector.name} is not available on ${type}.
- Unknown semantic attribute ${name}.
- :${name} requires a selector list.
- Unsupported selector node ${node.type}.
AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12).
Data as JSON: /api/errors/432b8f43340d89dc.
Report an issue: GitHub.