refract v0.1 · beta
Reference / Errors

Errors & troubleshooting

refract fails loudly at build — an invalid theme throws with a path-labelled message rather than emitting broken CSS. Every message below is verbatim from the library; each row is the cause and the fix. Messages are grouped by where you'll hit them.

Errors carry a stable code. Every authoring/build error is a RefractError with a machine-readable code (e.g. REFRACT_E_COLOR_INPUT, REFRACT_E_STEPS, REFRACT_E_NAMING) an agent or catch block can branch on without string-matching the message. Post-build reference validation collects all failures and throws them at once as REFRACT_E_VALIDATION — its .failures array lists every bad reference, so you fix them in one pass instead of one build at a time.

Colours

The strictest subsystem: colours must be tonally derivable — so a var(--…), currentColor or transparent is rejected, while hex, [r,g,b], oklch(), hsl(), rgb() and named keywords all work.

MessageCause → fix
Invalid colour "…". Author a colour as a hex string ("#4dabf7"), an [r, g, b] tuple, or a CSS colour — oklch(), hsl()/hsla(), rgb()/rgba(), or a named keyword (e.g. "rebeccapurple"). A var(--…) can't be tonally derived at build time.A colour value (base / text / a literal variant) was a var(--…), currentColor, or transparent — the only inputs refract rejects, because none can be tonally derived at build time. Fix: use a hex string, an [r, g, b] tuple, or any resolvable CSS colour (oklch(), hsl(), rgb(), a keyword).
Invalid colour tuple […]. Use an [r, g, b] tuple with 0–255 channels (alpha comes from an `alpha` variant, not the base).A tuple wasn't three 0–255 channels. Fix: [76, 110, 245]; author opacity as an alpha variant, not a 4th channel.
Unsupported hex length: "…". Use 3 or 6 digits.A 4- or 8-digit hex. Fix: 3- or 6-digit hex; alpha via an alpha variant.
colors.<name>.steps must be numbers in 0–1000 (e.g. [50, …, 950]); got …A steps entry was non-numeric or outside 0–1000 (the ladder maps each label to L = (1000 − label)/10). Fix: use ladder labels in 0–1000; for named tonal steps omit steps (you get light/lighter/dark/darker) or declare them as variants.
colors.<name>.variants.<v> needs one of darken / lighten / alpha / adjust.A derivation-spec variant object with no fn. Fix: give it exactly one of { darken } / { lighten } / { alpha } / { adjust }.
colors.<name>.variants.<v>.adjust.l must be an absolute OKLCH lightness in 0–100; got …An adjust dial out of range (l outside 0–100, c negative, or a non-numeric dial). Fix: l 0–100, c ≥ 0 (a multiplier), h a number of degrees.
colors.<name>.harmony: unknown scheme "…". Use one of complement, analogous, split-complement, triadic, tetradic.A harmony value that isn't a built-in scheme (or an object naming more than one). Fix: use one scheme name, or the { scheme: [names] } object form.
colors.<name> variant references unknown source "…".A variant's ref points at a token that doesn't exist. Fix: reference the base or an existing variant/step.
Cyclic colour variant derivation at colors.<name>.<v>.Two variants derive from each other. Fix: break the cycle — anchor one on the base.

Effects — shadows & transitions

MessageCause → fix
… must be structured shadow layer(s) or "none" — raw CSS strings are not accepted (received …).A shadow authored as a raw CSS string. Fix: use the structured form ({ offsetX, offsetY, blur, spread, color, inset }) or an array of layers, or "none".
… has unknown shadow field "…" (allowed: offsetX, offsetY, blur, spread, color, inset).A typo'd shadow key. Fix: use one of the six allowed fields.
….color must be a "colors.*" token-path string.A shadow's color was a literal, not a palette reference. Fix: reference a colour token (e.g. "colors.shadow.a20") — shadows theme via a translucent colour variant.
… must be structured transition part(s) or "none" — raw CSS strings are not accepted (received …).A transition authored as a raw CSS string. Fix: use the structured part form, an array, or "none".
… has unknown transition field "…" (allowed: …). · ….property is required (the CSS property to transition).A typo'd transition key, or a missing property. Fix: give each part a property plus duration/timingFunction/delay.
….timingFunction must be a keyword or cubic-bezier(...) string.An invalid easing. Fix: a keyword (ease, linear, …) or a cubic-bezier(...) string.

Layout — scales & recipes

MessageCause → fix
layout.<key>: declare only one of "ratio" (geometric) or "step" (linear) scale, not both.Two scale curves on one property. Fix: pick ratio (geometric) or step (linear).
layout.<key>: a geometric scale ("ratio") needs "steps" as an ordered name array, e.g. ["sm","md","lg"].A ratio scale without an ordered step-name array. Fix: supply steps: ["sm","md","lg"].
layout.<key>: a linear scale ("step") needs "steps" as a name→multiplier map, e.g. { sm:1, md:2, lg:3 }.A step scale without a name→multiplier map. Fix: supply steps: { sm: 1, md: 2, lg: 3 }.
layout.<key>: a responsive ramp entry needs a base scale — declare a top-level "ratio"/"step" (+ "steps") first.A responsive ramp without a base scale to ramp from. Fix: declare the base ratio/step (+ steps) first.
Unknown layout recipe property "…" in …. Known verbs: …An unknown key in a layout recipe. Fix: use a known verb (see the Layout recipes).

Globals

MessageCause → fix
globals: unknown preset "…" — expected one of preflight, normalize, reset or falseAn unrecognized globals.preset. Fix: use preflight, normalize, reset, or false.

Recipes & composition

MessageCause → fix
Recipe variant "…" is not defined in "<group>".A composition references a recipe variant that doesn't exist. Fix: check the subsystem:group.variant reference against what the subsystem actually declares.
Unknown recipe property "…" in … — expected a CSS property or a reserved key (variant, target, state, breakpoint, query, orientation, container, size).A recipe declaration key that's neither a real CSS property nor a reserved recipe key — usually a typo (ref: where you meant a variant: swap, colr: for color:). Caught so it can't ship as a stray literal. Fix: use the CSS property, or the reserved key you meant.
Cyclic recipe reference in "<group>": …Recipes reference each other in a loop. Fix: break the cycle.
components.<g>.<v>: css '<prop>' references unknown token '…' — check the token path, or use a bare string / number for a raw CSS valueA ref("…") in a component's css delta points at a token that doesn't exist. Fix: correct the path — or, if it's a raw CSS value, drop the ref() (a bare string in a css block is already a literal).
Recipe state entry … references unknown state "…".A states key the adapter doesn't know (the CSS adapter knows hover, disabled, …). Fix: use a state the target adapter declares in allowedStates.

Responsive, containers & modes

MessageCause → fix
Responsive recipe entry … references unknown breakpoint "…". / missing a "breakpoint" valueA responsive entry named a breakpoint that isn't in breakpoints, or omitted one. Fix: declare the breakpoint, or correct the name.
Responsive entry for "…" cannot set both "variant" and "target".variant (swap the active variant) and target (scope a rule to a variant) are opposites. Fix: pick one.
Container recipe entry … references unknown container "…".A container query named a container you didn't declare. Fix: declare it under containers. See Container queries.
Container recipe entry … cannot use "<field>" — container queries respond to a container's inline size, not orientation/height/aspect-ratio.An unsupported axis on a container query. Fix: query inline size only.
Breakpoint "…" is not defined.A media descriptor referenced an unknown breakpoint. Fix: add it to breakpoints.
Appearance mode "…" overrides nothing.A modes entry for a property that has no base to override. Fix: give the property a base value first.

Tokens

MessageCause → fix
Unknown token path "…".theme.resolveToken(path) was called with a path that isn't in the Model. Fix: check the path against theme.tokens (a flat path → Ref map).
Cyclic token reference: a -> b -> aAliases form a loop. Fix: break the alias cycle.

Build-time (CLI)

MessageCause → fix
No theme config found at …The CLI couldn't locate theme.config.*. Fix: run refract init, or pass --config. See Build-time.
"…" must export (default) a defineConfig({ raw, targets }) object.The config didn't default-export a defineConfig(...). Fix: export default defineConfig({ raw, targets }).
"…" has no targets to build.An empty targets array. Fix: add at least one { adapter, outDir }.
Adapter "…" does not implement emit(); it cannot build to disk.A run-time-only adapter used at build time. Fix: use an adapter that implements emit(), or compile at run time.
css adapter: emit mode '…' cannot be combined with the global inline option (inline bakes values, leaving no variables file)split/subsystem needs a variables file, but inline bakes values away. Fix: drop inline for those modes.
scss adapter: emit mode 'subsystem' is not supported yet · <adapter> adapter: emit mode '…' not yet implementedThat adapter doesn't support that emit mode. Fix: use single, or the CSS adapter for the richer modes. See the emit reference.
Every message is path-labelled (colors.brand.text — …) so it points at the exact authored location. If you hit one not listed here, it's an internal invariant (a library bug) — please file it.
Technical documentation for @theme-registry/refract · all output is compiled client-side by the real library (CSS adapter). The chrome is theme-aware; the render panes carry each preset's own world. · MIT licensed.