Repository navigation
sentrySvelteKit() deletes the adapter output directory (build/) on every serve-mode config load (vitest, vite dev) with @sveltejs/adapter-node 6 #25532
Description
Outcome
@sentry/sveltekit's vite plugin deletes the adapter output directory (default build/) on every vite config load in serve mode — any vitest run and any vite dev server start — when the project uses @sveltejs/adapter-node@6.
Background
In a SvelteKit 3 project (vite 8 / rolldown-vite, vitest 5) whose vite.config.ts contains sentrySvelteKit() (default options) and sveltekit({ adapter: adapter() }) from @sveltejs/adapter-node@6.0.0:
sentrySvelteKit()always adds thesentry-sveltekit-global-values-injection-plugin(whenautoUploadSourceMapsis the defaulttrue, regardless ofcommand).- That plugin's
configResolvedhook eagerly resolves the adapter output dir (getAdapterOutputDirinpackages/sveltekit/src/vite/svelteConfig.ts). getNodeAdapterOutputDir()learns the directory by executing the real adapter'sadapt()against a stub Builder: the stub'swriteClient(dest)recordsdestand throws to short-circuit.@sveltejs/adapter-node@6'sadapt()begins with a direct filesystem call —fs.rmSync(out, { force: true, recursive: true })(adapter-node/index.js, first statement) — which the stub Builder cannot intercept (adapter-node 5 routed this throughbuilder.rimraf(), which the stub no-ops). The realbuild/directory is deleted before the stub ever receives a call.
Because this happens in configResolved, it fires in serve mode too: every vitest run and every vite dev start wipes build/. In a vitest-then-e2e pipeline that serves the previously built output, the e2e web server dies with Cannot find module …/build.
Minimal reproduction
Any vitest run in such a project deletes build/. The call path can also be proven with no vite/vitest at all:
// repro.mjs — run from a SvelteKit app with @sentry/sveltekit and @sveltejs/adapter-node@6 installed
import { existsSync } from 'node:fs';
import { createRequire } from 'node:module';
import { dirname, join } from 'node:path';
import { pathToFileURL } from 'node:url';
import adapter from '@sveltejs/adapter-node';
const require = createRequire(import.meta.url);
const pkgDir = dirname(require.resolve('@sentry/sveltekit/package.json'));
const { getAdapterOutputDir } = await import(
pathToFileURL(join(pkgDir, 'build/esm/vite/svelteConfig.js')).href // src/vite/svelteConfig.ts when built from source
);
console.log('build/ before:', existsSync('build')); // true (after `vite build`)
const out = await getAdapterOutputDir({ adapter: adapter() }, 'node');
console.log('detected output dir:', out); // "build"
console.log('build/ after:', existsSync('build')); // false — deletedOutput:
build/ before: true
detected output dir: build
build/ after: false
Why the stub Builder can't help
The stub in getNodeAdapterOutputDir implements writeClient, log, getBuildDirectory, rimraf, mkdirp and config. adapter-node 6 does its cleanup with a direct fs.rmSync before it calls any Builder method, so executing adapt() at all is destructive, no matter how defensive the stub is.
Suggested directions
- Resolve the adapter output dir lazily/only in build mode (the value feeds source-map upload and global-value injection that only matter at build time), so serve-mode config loads never execute
adapt(). - Or stop executing the real adapter to learn the directory — e.g. read it from the adapter instance/config, or ask adapter authors to expose it.
Versions
@sentry/sveltekit11.6.0 (@sentry/bundler-plugins11.6.0)@sveltejs/kit3.0.1,@sveltejs/adapter-node6.0.0- vite 8.3.4, vitest 5.0.3, Node 24.20.0 (Windows; the
fs.rmSyncis platform-independent)
Metadata
Metadata
Assignees
Projects
- StatusShow more project fieldsWaiting for: Community
Activity
linear-code commentedon Oct 19, 2026
JS-3961
s1gr1d commentedon Oct 20, 2026
Thanks for the detailed repro! This is fixed in 11.7.0 (#25193): the probe now runs
adapt()from a temp directory, so your relativebuild/stays intact. Could you upgrade and confirm?And this issue is a duplicate of this one: #25186