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

  1. Open SEMANTIC_REGISTRY_V1[<your-type>] and confirm the attribute is in its attributes array.
  2. Move the attribute selector onto the element kind that actually declares it.
  3. 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 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


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