vitejs/vite · error · Error
There is already a server associated with the config.
Error message
There is already a server associated with the config.
What it means
Thrown by Vite's dev server factory when the ResolvedConfig object passed to createServer() is already registered in the internal usedConfigs WeakSet. Vite binds one dev server per resolved config to avoid duplicate servers, port conflicts, and shared mutable state (plugins, module graph) going out of sync.
Solutions
- Create a new ResolvedConfig per server by calling createServer(inlineConfig) with the raw inline config each time, letting Vite resolve internally.
- If you hold a ResolvedConfig, close the existing server (await server.close()) before starting a new one with the same config.
- For tests, resolve config inside beforeEach, not in a top-level shared variable.
Example fix
// before const config = await resolveConfig(cfg, 'serve') const s1 = await createServer(config) const s2 = await createServer(config) // throws // after const s1 = await createServer(cfg) await s1.close() const s2 = await createServer(cfg)
Defensive patterns
Strategy: validation
Validate before calling
// don't reuse ResolvedConfig across servers; pass InlineConfig each time const server = await createServer(inlineConfig)
Try / catch
try {
await createServer(config)
} catch (e) {
if (String(e?.message).includes('already a server')) {
await prevServer.close()
return createServer(inlineConfig) // fresh resolve
}
throw e
} Prevention
- Never share one ResolvedConfig between two createServer calls; close the old server first.
- In tests, resolve config per-test, not in a shared module-level constant.
When it happens
Trigger: Calling createServer(resolvedConfig) twice with the exact same ResolvedConfig instance returned by resolveConfig(...). Reusing a cached config across hot paths or test setup/teardown without creating a fresh one.
Common situations: Test suites that resolve config once for speed then spawn multiple servers. Framework integrations that cache resolveConfig output and call createServer on restart. Sharing the same config object between a build watcher and a dev server.
Related errors
- Cannot call server.listen in middleware mode.
- Cannot print server URLs before server.listen is called.
- Config was resolved for a "build", expected a "serve"…
- Cannot deep clone non-plain object
- Cannot merge config in form of callback
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/69cba91f46b82d8e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vite/src/node/server/index.ts:505
inlineConfig: ResolvedConfig | InlineConfig | undefined = {},
options: {
listen: boolean
previousEnvironments?: Record<string, DevEnvironment>
previousShortcutsState?: ShortcutsState<ViteDevServer>
previousRestartPromise?: Promise<void> | null
previousForceOptimizeOnRestart?: boolean
},
): Promise<ViteDevServer> {
// The dev server is a long-running, interactive process whose outputs
// (network responses, HMR updates) cannot be replayed from a cache.
disableCache()
const config = isResolvedConfig(inlineConfig)
? inlineConfig
: await resolveConfig(inlineConfig, 'serve')
if (usedConfigs.has(config)) {
throw new Error(`There is already a server associated with the config.`)
}
if (config.command !== 'serve') {
throw new Error(
`Config was resolved for a "build", expected a "serve" command.`,
)
}
usedConfigs.add(config)
const initPublicFilesPromise = initPublicFiles(config)
const { root, server: serverConfig } = config
const httpsOptions = await resolveHttpsConfig(config.server.https)
const { middlewareMode } = serverConfig
const resolvedOutDirs = getResolvedOutDirs(
config.root,View on GitHub (pinned to b4d66fee14)