Skip to content

root is overridden with a stale directory when one process resolves a second app's Vite config #17197

Closed

Description

@rymskip

Describe the bug

packages/kit/src/exports/vite/index.js captures the working directory once,
when the module is first evaluated:

// packages/kit/src/exports/vite/index.js:58 (main and 2.70.3)
const cwd = posixify(process.cwd());

and the config hook returns it as the project root:

// :333
root: cwd,

A tool that resolves more than one app's Vite config in the same process
therefore gets the first app's directory as the root of every later app. When
@sveltejs/load-config (the loader svelte-check uses) resolves a config, it
changes into that app's directory and passes root explicitly:

// @sveltejs/load-config@0.2.3 dist/src/index.js:125-127
const changeBack = changeCwd(root);
try {
    const resolved = await vite.resolveConfig({ root, configFile: configFilePath, logLevel: 'error' }, 'serve');

Kit's module is already cached from the first app, so its cwd still names that
app. The hook returns root: cwd, warn_overridden_config (:502) finds the
explicit root replaced, and prints:

The following Vite config options will be overridden by SvelteKit:
  - root

The warning is accurate: Vite computes the resolved root from config.root
after the config hooks run, so the second app's resolved config really is rooted
in the first app's directory. The same module-level cwd feeds server.fs.allow
through searchForWorkspaceRoot(cwd) and the paths process_config resolves
when options are passed through the Vite config. (svelte-check itself still
gets the right options, because it reads api.options, which kit loads from
svelte.config.js in the directory load-config changed into.)

It needs the apps to share one @sveltejs/kit install, as in a workspace, so
that a single module instance serves every config. A single app, or apps with
separate installs, never shows it, which is likely why #16293 could not be
reproduced in a fresh app.

The other reports of this message, #13376 and #15987, were the Windows
path-separator false positive fixed by #16037 in 2.65.2. This one reproduces on
macOS on 2.70.3, with that fix present.

Reproduction

https://github.com/rymskip/sveltekit-root-override-repro

Two SvelteKit apps in an npm workspace sharing one kit install. load-both.mjs
resolves each app's config in turn with @sveltejs/load-config.

npm install
npm run repro

Resolving a prints nothing; resolving b prints the warning above. Neither app
sets root.

Logs

> repro
> cd apps/a && node ../../load-both.mjs

resolving a
resolving b
The following Vite config options will be overridden by SvelteKit:
  - root

System Info

  System:
    OS: macOS 26.7
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 14.38 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 26.6.0
    npm: 11.18.0
  npmPackages:
    @sveltejs/kit: 2.70.3 => 2.70.3
    @sveltejs/load-config: 0.2.3 => 0.2.3
    @sveltejs/vite-plugin-svelte: 7.3.1 => 7.3.1
    svelte: 5.57.1 => 5.57.1
    vite: 8.3.0 => 8.3.0

Severity

annoyance

Additional Information

  • Where we hit it: svelte-check in one app of a monorepo whose apps alias each
    other's src/lib through kit.alias. It prints the warning once per sibling
    app config its ConfigLoader.loadConfig reaches, and the check itself passes.
  • A possible fix: derive the root inside the config hook from the config being
    resolved (config.root, falling back to process.cwd() at that moment) rather
    than from the module-level constant. load-config notes that changing directory
    "is only necessary for SvelteKit < 3", so the constant may already be on its
    way out.
  • load-config passes logLevel: 'error', but the warning goes straight to
    console.error, so the level cannot quiet it.

Activity

  1. svelte-triage-bot commented on Sep 24, 2026

    @svelte-triage-bot
    Contributor

    I could not reproduce the reported behavior from the instructions currently available.

    What I tried

    • Loaded root is overridden with a stale directory when one process resolves a second app's Vite config #17197 through the GitHub connection: The issue is open and reports the stale-root warning on @sveltejs/kit 2.70.3 when @sveltejs/load-config resolves two workspace apps in one process.
    • Cloned https://github.com/rymskip/sveltekit-root-override-repro at ecfb11703841cde0d050a4ac483b3cec8266a9ae, then ran npm install && npm run repro: The published 2.70.3 dependency reproduced the report exactly: app a resolved silently and app b emitted The following Vite config options will be overridden by SvelteKit: - root on stderr.
    • Checked out latest origin/version-3 at bf6833a and inspected packages/kit/src/exports/vite/index.js: The current target has no module-evaluation cwd. It already resolves root in a pre-config hook with vite_config.root ? path.resolve(vite_config.root) : process.cwd() and passes that per-resolution root through config processing.
    • Linked the reproduction to /workspace/repos/kit/packages/kit, removed the legacy svelte.config.js files required to exercise Kit 3, and ran npm run repro: Both app configs resolved in one process with exit code 0 and empty stderr; no overridden-root warning occurred.
    • Resolved both linked app configs directly with Vite and printed each resolved.root: The roots were /workspace/repros/sveltekit-root-override-repro/apps/a and /workspace/repros/sveltekit-root-override-repro/apps/b, respectively.
    • Checked the Kit working tree after the attempts: The issue branch remained clean; no product code or tests were changed, committed, or pushed.

    Observed blocker
    The bug is reproducible with the reported @sveltejs/kit 2.70.3, but it cannot be reproduced in the required latest default branch (version-3). That branch already derives root per Vite config resolution and returns the correct root for both workspace apps, so no failing test or justified patch can be produced in this checkout.

  2. rymskip commented on Sep 24, 2026

    @rymskip
    Author

    sorry I thought main was default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions