amruthpillai/reactive-resume · error · Error
Attribute ${selector.name} is not available on ${type}.
Error message
Attribute ${selector.name} is not available on ${type}. What it means
Thrown by validateCompound when an attribute selector uses a globally-recognized attribute name that is not declared on the specific semantic element type present in the same compound. Each kind in SEMANTIC_REGISTRY_V1 owns its own attributes array; 'id' and 'role' are exempted because they apply to all kinds.
Source
Thrown at packages/resume/src/stylesheet/selector.ts:137
const types = selectors.filter(
(selector): selector is Extract<CompiledSimpleSelector, { type: "type" }> => selector.type === "type",
);
if (types.length > 1) throw new Error("A compound selector can contain only one type selector.");
const type = types[0]?.name ?? null;
for (const selector of selectors) {
if (selector.type !== "attribute") continue;
if (selector.name === "id") continue;
if (selector.name === "role") {
if (!roleValueIsKnown(selector.matcher, selector.value, allowedRoles(type))) {
throw new Error("Selector uses an unknown role.");
}
continue;
}
if (type && !(SEMANTIC_REGISTRY_V1[type].attributes as readonly string[]).includes(selector.name)) {
throw new Error(`Attribute ${selector.name} is not available on ${type}.`);
}
}
}
function compileNth(
node: SelectorAst,
name: "nth-child" | "nth-of-type",
context: CompileContext,
): CompiledSimpleSelector {
const nth = childrenOf(node);
if (nth.length !== 1 || nth[0]?.type !== "Nth" || !nth[0].nth) {
throw new Error(`:${name} requires one An+B expression.`);
}
const expression = nth[0].nth;
let a = 0;
let b = 0;
if (expression.type === "Identifier") {View on GitHub (pinned to 3a5b12e2a4)
Solutions
- Open SEMANTIC_REGISTRY_V1[<your-type>] and confirm the attribute is in its attributes array.
- Move the attribute selector onto the element kind that actually declares it.
- Remove the attribute selector if it is not meaningful for that type.
Example fix
// before page[type='experience'] // after section[type='experience']
Defensive patterns
Strategy: validation
Validate before calling
import { SEMANTIC_REGISTRY_V1 } from '@reactive-resume/resume';
const attributeAllowedOn = (type, attr) =>
attr === 'id' || attr === 'role' ||
(SEMANTIC_REGISTRY_V1[type]?.attributes ?? []).includes(attr);
// call before combining a type selector with an attribute selector Type guard
const isRejected = (r) => r.selector === null && typeof r.error === 'string';
Try / catch
const result = compileSelector(selector);
if (result.selector === null) {
// result.error starts with 'Attribute' and ends with 'is not available on ...'
reportToSelectorAuthor(result.error, selector);
} Prevention
- When moving a selector between element kinds, re-check the target kind's attributes array.
- Only id and role are universal; every other attribute is type-scoped.
- Lint selectors against SEMANTIC_REGISTRY_V1 in CI.
When it happens
Trigger: Writing page[type] (type belongs to section), resume[placement] (placement belongs to region/section), or section[page-number] where the attribute belongs to a different kind.
Common situations: Assuming an attribute is universal because it works elsewhere; refactoring a selector from one element kind to another without re-checking that kind's attribute list; auto-complete suggesting attributes from a different type.
Related errors
- Unknown semantic attribute ${name}.
- Selector uses an unknown role.
- Unknown semantic element ${name}.
- Unsupported attribute matcher ${matcher}.
- Attribute selector matcher and value must be used together.
AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12).
Data as JSON: /api/errors/ee8f31e3c4ed76a7.
Report an issue: GitHub.