Troubleshooting
Exact error text → root cause → fix, for every failure mode hit while running real consume tests.
Last updated
Errors below are verbatim from real runs. Find yours, apply the fix. If you hit something not listed, that's a doc bug — report it with the exact output.
Before reading further, run the setup check — it catches the most common misconfigurations, including the two silent ones below:
pnpm exec vegastack-design doctorIt also scans your own source — not node_modules, build output, or the
components.json ui directory — for vocabulary the shadcn reset retired:
text-h1…text-h4, text-label, text-mono-label, text-strong,
text-display-*, the status *-subtle steps, --alpha-*, --opacity-*,
--z-*, shadow-overlay, backdrop-blur-glass, and imports of the retired
components (icon-button, segmented, progress-indicator,
field-inline, floating-surface, section-header, sonner). Each compiles
to nothing, so it fails the run with the file:line and the replacement.
A custom property your project declares itself (--z-header: 30) is yours and
is not reported.
It also warns where your code works around a part instead of using it: a
Tailwind ! modifier in the className of a part imported from the ui
directory (gap-0!, !p-1); a w-*, min-w-* or max-w-* class on a
popover, menu, select or combobox popup (PopoverContent takes size —
default, md, lg, fit — and menus size to their longest item); a
hand-written <header> inside SheetContent, DrawerContent, DialogContent
or AlertDialogContent in the same file (use the overlay's own header part);
and an AppShellPage in an App Router page/layout file whose size differs
from the route map (see Page layout). These are
warnings, so a release that adds one never turns your build red; once you have
fixed them, run vegastack-design doctor --strict in CI to make them failures.
The scan is lexical and errs toward silence: a part re-exported through your own
module, or a <header> rendered by a child component, is not seen.
Coming from 0.4.x? Most of what breaks there is not a bug — it is the shadcn reset. Work Migrating to the shadcn reset first; its section 13 lists the silent failures (a deleted token compiles to nothing and the page just looks wrong).
Install & build
Can't resolve 'tw-animate-css' in '…/node_modules/@vegastack/design'
Build error the moment preset.css is imported. Two different causes — check the
second one first if you are on a current version.
Cause 1 (most likely today): no Tailwind PostCSS plugin. Without
@tailwindcss/postcss configured, Tailwind's engine never runs, so the bundler's
own CSS pipeline tries to resolve preset.css's @import "tw-animate-css" and
fails. The error names a dependency, but the dependency is fine — nothing is
missing. Under Turbopack (the Next 16 default) this fails the build; under webpack
the import resolves and you get the silent variant instead (next entry).
Fix: add the plugin, then rebuild.
const config = { plugins: { "@tailwindcss/postcss": {} } };
export default config;pnpm add -D @tailwindcss/postcsspnpm create next-app --tailwind writes this file for you, which is why the
Quickstart never mentions it. Scaffolding by hand, adding VegaStack to an existing
app, or building a monorepo app all skip that step.
Cause 2 (legacy): @vegastack/design older than 0.1.1, which marked
tw-animate-css as an optional peer that pnpm never installs.
Fix: pnpm update @vegastack/design (≥ 0.1.1). If you are already on a newer
version, this is not your problem — see Cause 1.
Build succeeds, colours and fonts work, but no utility classes exist
The worst failure mode in the consume path, because nothing errors. p-4,
flex, text-muted-foreground and every other utility do nothing, while the
theme looks broadly right.
Cause: no @tailwindcss/postcss plugin (as above). The token theme is
literal CSS inside preset.css, so :root/.dark custom properties land
regardless — but every utility class has to be generated by Tailwind, and
without the plugin Tailwind never runs. The result reads as "the design system is
broken" when the design system was never invoked.
Fix: the postcss.config.mjs above.
Confirm it: the emitted stylesheet should contain real utility selectors, not
just variables.
# after a build — expect a non-trivial count, not 0
grep -o '\.[a-z][a-z0-9-]*{' .next/static/**/*.css | wc -lCannot find module '@vegastack/design/theme.css' (or base/utilities)
Cause: an import path outside the exports map — usually
@vegastack/design-tokens/theme.css in an app that never installed the tokens
package (it's transitive; pnpm-strict hides it).
Fix: import the re-exports: @vegastack/design/theme.css etc. Apps should
never import @vegastack/design-tokens/* directly.
Tailwind utilities exist but everything is unstyled
Cause: app/globals.css still contains create-next-app's own
@import "tailwindcss" block instead of (or as well as) the preset.
Fix: the file should contain exactly one entry:
@import '@vegastack/design/preset.css'; — the preset imports Tailwind itself.
Registry & CLI
shadcn add → 403 (or "Failed to fetch registry")
curl -s -o /dev/null -w "%{http_code}" \
-H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET" \
https://design.vegastack.com/r/registry.json- curl 403 too → the values are wrong: expired token, or the classic
header-name-in-value mistake (
CF-Access-Client-Id: abc…stored as the value). See Registry access & auth. - curl 200 but the CLI fails → the CLI isn't seeing your env:
.env.localnot in the directory you're running from, or the shell doesn't export the vars. Run from the project root; checkcomponents.jsonuses${CF_ACCESS_CLIENT_ID}placeholder syntax exactly.
Component installed but looks/behaves wrong (Radix imports inside)
Cause: a bare shadcn add dialog — without @vegastack/, you got shadcn's
own Radix-based component (and possibly overwrote ours).
Fix: git checkout the file, re-add with the namespace:
pnpm dlx shadcn@latest add @vegastack/dialog. Grep check:
grep -r "@radix-ui" components/ui/ should return nothing.
shadcn init hangs forever
Cause: the CLI is waiting on an interactive prompt (non-tty shells, CI,
agents).
Fix: skip init — write components.json yourself; the complete known-good
file is in the Quickstart §4. Init is a convenience,
not a requirement.
vegastack-design: command not found
Cause: running it bare, outside a project that has @vegastack/design
installed.
Fix: pnpm exec vegastack-design … inside the project (the bin ships with
the package), or one-off anywhere:
npx --package=@vegastack/design vegastack-design ….
Runtime
toast.add(...) does nothing — no error, no toast
The #1 report. Cause: no VegaStackProvider above the calling component (or
at all). Fix: Provider setup. Related: toasts
appearing twice → two Toasters mounted; pass toaster={false} to one.
Hydration warning: server class="…" didn't match client, mentions <html>
Cause: missing suppressHydrationWarning on <html> — next-themes sets the
theme class pre-hydration.
Fix: add the attribute (Quickstart §6). This suppresses only that one
attribute's check, nothing else.
Dialog / dropdown renders under the page header
Cause: the body { isolation: isolate } stacking context from base.css
isn't applied — usually a granular-import setup that skipped base.css, or a CSS
layer conflict overriding isolation.
Fix: import the preset (it includes base.css), or re-add
body { isolation: isolate }. Never "fix" this with z-index arms races.
No focus outline anywhere when tabbing
Cause: same as above — base.css skipped. Components intentionally carry no
per-component focus ring; the global :focus-visible outline is the mechanism.
Fix: import the preset. This is a WCAG failure, not a cosmetic issue — treat
as ship-blocking.
Not a bug: a focused text input shows no outline and no background change —
its border darkens subtly instead. That is the design — a text field cannot tell
mouse from keyboard, so the border (on :focus, not just keyboard focus) is the
one cue for both (FOC-14's text-entry exception, MK 2026-09-27).
Tooltips each wait ~600ms even when moving across a toolbar
Cause: no provider → no shared Base UI Tooltip.Provider delay group.
Fix: Provider setup.
Updates
check-updates says it "could not reach the registry"
Every registry request already gets three tries with a short, jittered backoff: a network error, a
response cut off mid-read ("terminated"), a 5xx or a 429 (its Retry-After, seconds or a date, honoured up to 5 seconds) is retried
before anything is reported, and item fetches run at most eight at a time. So this message means
the registry was unreachable for several seconds, not a one-off blip: check the runner's network,
the registry URL and its Access credentials. A 404, a 401/403 or an integrity mismatch is an
answer, never retried, and fails at once.
check-updates says "No VegaStack components found" despite copied components
Cause 1 (layout): it is looking in the wrong directory. It resolves
components.json's aliases.ui by stripping a leading @/, then tries that path
and a src/ variant. Any layout those two guesses miss — a monorepo package, or a
@/* alias mapped somewhere else through tsconfig paths — scans nothing.
Fix: point it at the real directory.
vegastack-design check-updates --dir packages/ui/src/components/uiMake that the committed form of the script, not something you type once. A drift
gate scanning the wrong directory is worse than no gate — which is why
--fail-on-update now exits 1 when it finds zero components, instead of
passing vacuously.
Cause 2 (legacy): @vegastack/design older than 0.1.1, whose check-updates
only recognized files with provenance headers — which the current shadcn CLI strips
on copy-in.
Fix: pnpm update @vegastack/design. Current versions identify components by
filename against the registry index and compare content — no header needed.
check-updates says up to date but the registry version number is higher
Not a bug. Each component carries its own version, the release in which its content last changed. A newer design-system release that did not touch that component leaves it as it is, so there is nothing to pull.
? <name> — not in registry (renamed/removed)
The component was renamed or retired upstream. Check the
Changelog for the mapping; the copy in your repo keeps working
regardless (you own it) — migrate when convenient. Caveat: this status only
appears for files that still carry a provenance header (older CLIs / other
tooling). A headerless copy of a retired component silently drops out of the
report — after a rename lands in the changelog, grep components/ui/ for the old
filename yourself.
--overwrite clobbered my customizations
Expected — overwrite replaces the file. Your edits are in git:
git diff HEAD~1 -- components/ui/<name>.tsx, re-apply on top, run your smoke
tests. Prevention: review with --diff first, keep customizations additive, or
compose in wrapper files instead of editing the copy.
For agents: prefer exact-error-text search on this page over improvising. If a fix requires credentials or accounts (tokens, npm, Cloudflare), surface to a human — never work around an auth boundary.