amruthpillai/reactive-resume · error · Error

Unknown semantic attribute ${name}.

Error message

Unknown semantic attribute ${name}.

What it means

Thrown by compileSimple in the AttributeSelector branch when the attribute name is not in the knownAttributes set (the union of 'id', 'role', and every attributes array across SEMANTIC_REGISTRY_V1). Matching is case-sensitive, so [TYPE] is rejected even if [type] is valid.

Source

Thrown at packages/resume/src/stylesheet/selector.ts:190

	if (name === "nth-of-type" && nth[0].selector) throw new Error(":nth-of-type does not accept an of selector.");
	const of = nth[0].selector ? compileSelectorList(nth[0].selector, { depth: context.depth + 1 }) : undefined;
	return { type: "pseudo", name, a, b, ...(of ? { of } : {}) };
}

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" };
			}

View on GitHub (pinned to 3a5b12e2a4)

Solutions

  1. Use a lowercase attribute name that appears in the registry (id, role, type, placement, region, part, page-number, level, direction, name, owner, origin, template).
  2. For custom targeting, use [id='...'] or a structural selector instead of an unregistered attribute.
  3. Check spelling and case against the SEMANTIC_REGISTRY_V1 export.

Example fix

// before
[TYPE='experience']
// after
[type='experience']
Defensive patterns

Strategy: validation

Validate before calling

import { SEMANTIC_REGISTRY_V1 } from '@reactive-resume/resume';

const KNOWN_ATTRS = new Set(['id', 'role', ...Object.values(SEMANTIC_REGISTRY_V1).flatMap(d => d.attributes)]);
const attributeIsKnown = (name) => KNOWN_ATTRS.has(name.toLowerCase()) && KNOWN_ATTRS.has(name); // case-sensitive
// verify attribute names (case-sensitive) before compiling

Type guard

const isRejected = (r) => r.selector === null && typeof r.error === 'string';

Try / catch

const result = compileSelector(selector);
if (result.selector === null && result.error.startsWith('Unknown semantic attribute ')) {
  lowerCaseOrSuggestAttribute(selector);
}

Prevention

When it happens

Trigger: Writing [unknown], [TYPE], [data-x], or any attribute not declared anywhere in the registry.

Common situations: Using HTML data-* attributes; uppercase attribute names; typos; attributes from a newer/older schema version.

Related errors


AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12). Data as JSON: /api/errors/1aa4436f69514f45. Report an issue: GitHub.