Date: 2026-05-20
Branch: release/dashboard-alpha
Affected app: apps/dashboard (Storybook via @storybook/sveltekit)
Storybook fails to start due to a version mismatch between @sveltejs/vite-plugin-svelte at the npm workspace root and the version expected by the dashboard app and Storybook itself. npm's hoisting algorithm resolves an incompatible older version (6.x) to the root node_modules, while the apps use a local override (7.x). Storybook's deep dependency chain resolves the root version, not the workspace-local one, causing the build to crash.
This monorepo uses npm workspaces. apps/dashboard (and apps/client) explicitly require:
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"vite": "^8.0.13"@sveltejs/vite-plugin-svelte 7.x requires vite: "^8.0.0-beta.7 || ^8.0.0" as a peer.
However, when npm install resolves the full workspace dependency tree a self-locking cycle takes hold, driven by @sveltejs/vite-plugin-svelte-inspector@5.0.2:
@sveltejs/vite-plugin-svelte@6.2.4 (hoisted to root as a peer dep)
└─ depends on → @sveltejs/vite-plugin-svelte-inspector@^5.0.0
├─ peers against → @sveltejs/vite-plugin-svelte@^6.0.0-next.0 ← 6.x ONLY, non-optional
└─ peers against → vite@^6.3.0 || ^7.0.0 ← excludes vite 8
Inspector@5 is the only package in the tree whose peer range for @sveltejs/vite-plugin-svelte excludes 7.x. Its vite@^6.3.0 || ^7.0.0 peer constraint prevents vite 8 from being hoisted to root. With root vite locked to 7.x, @sveltejs/vite-plugin-svelte@7.x (which requires vite@^8) cannot be hoisted either — so 6.2.4 wins the root slot, which keeps inspector@5 installed, which keeps the cycle closed.
npm resolves the resulting conflict by creating workspace-level overrides:
apps/client/node_modules/@sveltejs/vite-plugin-svelte@7.1.2+apps/client/node_modules/vite@8.0.13apps/dashboard/node_modules/@sveltejs/vite-plugin-svelte@7.1.2+apps/dashboard/node_modules/vite@8.0.13
Why Storybook breaks: Storybook packages live under root node_modules/@storybook/.... Node's module resolution walks up from there and finds the root node_modules/@sveltejs/vite-plugin-svelte@6.2.4 — not the workspace-local 7.1.2. With vite 8.x in use (from the workspace overrides), @sveltejs/vite-plugin-svelte@6.2.4 either throws a peer validation error or behaves incorrectly against the vite 8 API, breaking the Storybook build/dev server.
| Package | Before (broken) | After (fixed) |
|---|---|---|
root node_modules/vite |
7.3.1 |
8.0.13 |
root node_modules/@sveltejs/vite-plugin-svelte |
6.2.4 |
7.1.2 |
apps/*/node_modules/@sveltejs/vite-plugin-svelte |
7.1.2 (workspace override) |
(removed — root now satisfies) |
apps/*/node_modules/vite |
8.0.13 (workspace override) |
(removed — root now satisfies) |
The fix ensures the root-level hoisted versions are also 7.x / vite 8.x, removing the need for workspace-level overrides. This works because @sveltejs/vite-plugin-svelte@7.x dropped @sveltejs/vite-plugin-svelte-inspector as a dependency entirely — without inspector@5 in the tree, the vite@^7 constraint is gone and npm can hoist vite 8 and vite-plugin-svelte 7 to root without conflict.
The broken state can sneak back in if a future @sveltejs/vite-plugin-svelte release reintroduces inspector (or any other package that peers against vite@<8 and @sveltejs/vite-plugin-svelte@^6). Before removing the Option A overrides, verify any reintroduced inspector version accepts vite@^8.
To re-apply the fix if the issue recurs:
Add to the root package.json:
"overrides": {
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"vite": "^8.0.13"
}Then run:
npm installThis forces npm to always resolve these packages to compatible versions across the entire workspace tree, preventing the broken state from being re-introduced.
rm -rf node_modules package-lock.json
npm installIf the broken state re-appears in package-lock.json, check for any package that peers against @sveltejs/vite-plugin-svelte@^6.x or vite@<8 with a non-optional, non-wide range. The known historical culprit is @sveltejs/vite-plugin-svelte-inspector@5.x. Find it with:
npm ls @sveltejs/vite-plugin-svelte --all 2>/dev/null | grep -v "deduped\|UNMET"
npm ls vite --all 2>/dev/null | grep -v "deduped\|UNMET"If the bad resolution originates from a Storybook package peer-requiring an older vite-plugin-svelte, pinning Storybook versions prevents silent upgrades from re-triggering it:
"overrides": {
"@storybook/sveltekit": "10.4.0",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"vite": "^8.0.13"
}After applying the fix, confirm the correct versions are at the root:
cat node_modules/@sveltejs/vite-plugin-svelte/package.json | grep '"version"'
# should print "7.x.x"
cat node_modules/vite/package.json | grep '"version"'
# should print "8.x.x"
npm run storybook --workspace=apps/dashboard
# should start without errorsIf this regresses, the Storybook error will typically look like one of:
Error: Vite peer dependency mismatch: @sveltejs/vite-plugin-svelte requires vite@^8 but found vite@7Cannot find module 'vite/...'from within@sveltejs/vite-plugin-svelte- Storybook builder silently using wrong vite config transforms, producing a blank/broken UI
Quick check:
node -e "console.log(require('./node_modules/@sveltejs/vite-plugin-svelte/package.json').version)"
# If this prints 6.x, the bug has returned