Velareference

Diagnostics

Every diagnostic code, how it reaches your build or editor, and the ones easy to miss.

On the compile-time path, Vela reports most of what it cannot lower. This page lists every code it produces, what to do about the ones you will actually hit, and where nothing is reported at all.

How diagnostics reach you

The compiler produces diagnostics. The host adapter maps them into rbxtsc’s diagnostic list, using this message format:

[@vela-rbxts/compiler] unknown-theme-key: Unknown theme key "brand-500" for background color utility in className literal.

The bracketed prefix is the phase: @vela-rbxts/compiler for anything found in your classes, @vela-rbxts/rbxtsc-host for the one diagnostic the adapter synthesizes. Numeric codes are diagnosticCodeBase + index per file, the base defaulting to 89000, so the numbering restarts for each file. The category comes from the diagnostic’s level and defaults to Warning.

Code table

Every code is a warning unless marked otherwise.

Families, variants, and payload shapes

CodeFires when
unsupported-utility-familyThe token does not match any known utility family — including typos
no-roblox-equivalentA real Tailwind family that cannot be expressed in Roblox UI (tracking-*, blur-*, cursor-*, …); the message names the family
unknown-variantA colon prefix that is not a supported variant; the message lists the set, the configured breakpoints, and the attr-[…] form
unknown-breakpointSince 0.13.0: a max- in front of something that is not a breakpoint. The message names the configured ones and points at theme.screens
invalid-breakpoint-rangeSince 0.13.0: a chain whose width bounds leave no viewport, as lg:max-md: or md:max-md:. Emitting it would produce a rule that never fires
malformed-attribute-variantSince 0.13.0: an attr-[…] that does not parse — brackets left open, or no value to compare against. The message names which
unsupported-arbitrary-valueA [...] payload the family cannot read — w-[abc], bg-[notacolor], font-[600]. Since 0.7.0 most length families do read brackets, and since 0.12.3 a space inside them does not split the token, so w-[calc(100% - 4px)] reports this once rather than three times; see arbitrary values
unsupported-opacity-modifierA /N opacity modifier on a family with no transparency channel. Since 0.12.0 that is placeholder-* alone, and the message says why

Theme and color

CodeFires when
unknown-theme-keyA color, radius, spacing, or font-family key is absent from the theme
unsupported-color-keycurrent or inherit, or transparent on a property with no transparency channel
color-missing-shadeA palette family referenced without a shade, and that palette has no DEFAULT
color-invalid-shadeA literal given a shade, or a palette missing that shade
unsupported-size-spacing-valueA spacing value used for a size is not offset-only

Per-value rejections

Each family that accepts a closed set of values has its own code, so the message always tells you which family rejected what:

CodeFamily
unsupported-border-valueborder-* styles, sides, and off-list thicknesses. A /N modifier is no longer among them — since 0.12.0 border-slate-500/25 resolves
unsupported-stroke-valuering-* / outline-* off-list values, inset, offset-*
unsupported-rotation-valuerotate-* outside the degree list
unsupported-scale-valuescale-* outside the value list
unsupported-opacity-valueopacity-* not an integer 0–100
unsupported-aspect-valueaspect-* outside square, video, valid brackets
unsupported-flex-directionflex-* that is neither a direction nor a flex-item keyword
unsupported-alignment-valueAn unresolvable justify-*, items-*, or content-*
unsupported-grid-valueA grid-cols-*/grid-rows-* count outside 1–12
unsupported-layout-order-valueAn unresolvable order-*
unsupported-space-valueAn unresolvable space-x-*/space-y-*
unsupported-margin-valueAn unresolvable margin payload
unsupported-negative-margin-mr-* or -mb-* — only top/left margins can be negative. Since 0.12.4 a side holds one signed value and the last class written to it wins; see margin
unsupported-divide-valueAn unresolvable divide-* payload
unsupported-line-height-valueA leading-* outside the six named keys
unsupported-text-sizeA text-{size} that cannot be resolved (not reachable in practice)
unsupported-font-weightfont-{x} is not a known weight name (not reachable since 0.7.0 — see below)
unsupported-text-alignmenttext-justify, or an align-* outside top/middle/bottom
unsupported-whitespace-valueA whitespace-* outside normal/nowrap
unsupported-gradient-directionbg-gradient-to-{x} with a direction outside the eight
unsupported-shadow-insetshadow-inner
unsupported-overflow-valueoverflow-* other than hidden, clip, visible
unsupported-anchor-valueorigin-{x} outside the nine origin keys
unsupported-object-fit-valueAn object-* outside cover/contain/fill/tile
unsupported-pointer-events-valueA pointer-events-* outside none/auto
unsupported-overscroll-valueAn overscroll-* outside auto/contain/none
unsupported-scroll-valueA scroll-* outside x/y/xy/none — which is where Tailwind’s scroll-smooth and scroll-m-* land
unsupported-transition-valueAn unresolvable transition/duration/delay/ease payload. transition-shadow stopped landing here in 0.13.0, when transitions began moving the helper instances
unsupported-animation-valueAn animate-* outside the presets

Z-index gets four codes of its own: z-auto is unsupported-z-index-auto, a negative -z-N is unsupported-negative-z-index, a fractional z-[1.5] is unsupported-arbitrary-z-index, and any other unbracketed number is unsupported-z-index-value. A whole-number z-[15] resolves.

font-* falls through to unknown-theme-key. The prefix resolves the fixed weight names first and reads anything else as a key in theme.fontFamily. font-nope, font-600 and font-extrablack all report unknown-theme-key. unsupported-font-weight still exists in the code table, but no payload reaches it.

Contextual warnings

CodeFires when
transition-without-runtimetransition/duration-*/ease-*/delay-* on an element with no variant rules and no dynamic className — there is nothing to animate, so the tokens are dropped
motion-on-componenttransition-* or animate-* on a component element — motion needs a real instance to drive
decoration-on-richtextunderline/line-through on an element that already sets RichText itself — Vela backs off rather than double-wrapping your markup
classname-on-unsupported-hostBuild only. className sits on a JSX element that is neither a supported host element nor a component
unsupported-host-utilityEditor only. The utility is not allowed on that host element tag

Errors

CodeFires when
tsx-parse-failedThe file failed to parse, or parsed with recovered errors
tsx-emit-failedCode generation failed after a successful transform
invalid-config-jsonThe resolved config JSON handed to the compiler is malformed; the file falls back to the default theme
compiler-invocation-failedThe native compiler call threw; synthesized by the host adapter

The errors are structural rather than about your classes.

compiler-invocation-failed has one cause common enough to name. The host adapter resolves typescript from your project and calls into its API. TypeScript 7 surfaces here as Cannot read properties of undefined (reading 'Latest') on the first file. Pin typescript@5.9.3. Everything else under this code is the native binding failing to load or throwing.

classname-on-unsupported-host is the one that tells you nothing happened. Vela lowers className on the eight supported host elements and on components. Anything else keeps the attribute verbatim and warns:

Warns, and the className survives untouched
<screengui className="bg-slate-700" />

That bucket is everything neither host nor component — lowercase intrinsics such as screengui, and namespaced tags such as <svg:rect />, which never count as components. The message names only the local part, so <svg:rect /> is reported as rect. Move the classes onto a frame inside the element, or onto a component that forwards them.

This one is build only: the editor surface never collects an unsupported element, so it never emits this code.

unsupported-host-utility never appears in a build. The per-element restrictions it reports are checked by the editor surface alone. <frame className="text-red-500" /> compiles and emits a TextColor3 assignment on a Frame with no complaint. Treat it as an editor-only lint. It is never raised on a component either, since the host element behind <Panel /> is unknown.

The runtime path does enforce the rule, silently. A utility the host element cannot carry is dropped rather than written, since the assignment would be a hard Roblox error. The same class list behaves differently on the two paths, and neither reports anything at build time.

The ones you will actually hit

unsupported-utility-family

A class Vela does not recognize at all — usually a typo. The token is dropped and the element compiles normally.

A typo
<frame className="shadwo-lg rounded-lg" />

rounded-lg is applied, and shadwo-lg is dropped with a warning. The same code covers typos and genuinely unknown families, so read the token before concluding a feature is missing.

no-roblox-equivalent

You wrote a real Tailwind utility that Roblox UI cannot express. The message names the family and says the token is ignored:

Compiler output
[@vela-rbxts/compiler] no-roblox-equivalent: Tailwind "tracking" utilities have no Roblox equivalent, so "tracking-wide" is ignored.

This is a design decision, not a roadmap gap — the not-implemented table gives the reason per family and what to reach for instead.

unknown-theme-key

The class parsed fine, but the key it looked up is not in the resolved theme. The family in the message tells you which scale was searched: colors, radius, or spacing.

Fails
<frame className="rounded-huge p-0.25" />

rounded-huge fails because rounded-* is a pure theme lookup and huge is not one of the default radius keys — add it under theme.extend.radius or use 4xl. p-0.25 fails because the spacing fallback only accepts multiples of 0.5. Use p-0.5.

The most common form of this one is subtler. A color you thought you defined in theme.extend.colors will report unknown-theme-key if your config also sets a top-level theme.colors, because that combination silently discards extend. See the callout in Configuration.

color-missing-shade

You named a palette family without a shade, and that palette has no DEFAULT to fall back on.

Fails, if your brand palette defines only 500 and 700
<frame className="bg-brand" />
Compiler output
[@vela-rbxts/compiler] color-missing-shade: Color palette "brand" for background color utility has no "DEFAULT" shade, so it requires an explicit shade such as "brand-500" in className literal.

Either write the shade, as bg-brand-500, or add a DEFAULT key to the palette in theme.extend.colors so the bare form resolves. Literal colours are always usable without a shade. That covers black, white, and anything you define as a plain string. Every built-in palette ships a DEFAULT, so bg-slate works out of the box.

color-invalid-shade

Either you gave a literal a shade, or you asked a palette for a shade it does not have.

Fails
<frame className="bg-white-500 text-brand-400" />

bg-white-500 fails because white is a literal — write bg-white. text-brand-400 fails if your brand palette only defines 500 and 700 — add 400, or use a shade you defined. Palettes do not interpolate missing shades.

Editor-only filtering

The editor surface applies one filter the build does not. It suppresses unknown-theme-key while the payload you have typed so far is still a prefix of a real theme key. As you type bg-sla on the way to bg-slate-800, no squiggle flashes, because sla can still become slate. bg-nope warns immediately, because no theme key starts with nope.

A wrong key that happens to be a prefix of a real one, such as bg-sl or bg-slat, looks fine in the editor. It still warns in the build. Codes other than unknown-theme-key are never filtered, so color-missing-shade on a DEFAULT-less palette shows up immediately.

See also