{"id":"69cba91f46b82d8e","repo":"vitejs/vite","slug":"there-is-already-a-server-associated-with-the-conf","errorCode":null,"errorMessage":"There is already a server associated with the config.","messagePattern":"There is already a server associated with the config\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vite/src/node/server/index.ts","lineNumber":505,"sourceCode":"  inlineConfig: ResolvedConfig | InlineConfig | undefined = {},\n  options: {\n    listen: boolean\n    previousEnvironments?: Record<string, DevEnvironment>\n    previousShortcutsState?: ShortcutsState<ViteDevServer>\n    previousRestartPromise?: Promise<void> | null\n    previousForceOptimizeOnRestart?: boolean\n  },\n): Promise<ViteDevServer> {\n  // The dev server is a long-running, interactive process whose outputs\n  // (network responses, HMR updates) cannot be replayed from a cache.\n  disableCache()\n\n  const config = isResolvedConfig(inlineConfig)\n    ? inlineConfig\n    : await resolveConfig(inlineConfig, 'serve')\n\n  if (usedConfigs.has(config)) {\n    throw new Error(`There is already a server associated with the config.`)\n  }\n\n  if (config.command !== 'serve') {\n    throw new Error(\n      `Config was resolved for a \"build\", expected a \"serve\" command.`,\n    )\n  }\n\n  usedConfigs.add(config)\n\n  const initPublicFilesPromise = initPublicFiles(config)\n\n  const { root, server: serverConfig } = config\n  const httpsOptions = await resolveHttpsConfig(config.server.https)\n  const { middlewareMode } = serverConfig\n\n  const resolvedOutDirs = getResolvedOutDirs(\n    config.root,","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/vitejs/vite/blob/89620f09afcfef6b35e7bb8660132ab5b4d0cd3b/packages/vite/src/node/server/index.ts#L487-L523","documentation":"createServer at packages/vite/src/node/server/index.ts:505 keeps a WeakMap (usedConfigs) from resolved config objects to the dev server they back. Calling createServer twice with the same ResolvedConfig instance throws, because a config is meant to back at most one server and the second call would share mutable state (plugins, caches) in unsafe ways.","triggerScenarios":"Awaiting resolveConfig once and passing the result to createServer in two places; a test helper that calls createServer(config) without re-resolving; restarting logic that reuses the previously resolved config instead of resolving a fresh one.","commonSituations":"Custom harnesses caching the resolved config; integration tests sharing fixtures; frameworks that call createServer internally after the user already did.","solutions":["Resolve a fresh config for each server (pass an InlineConfig, not a ResolvedConfig) so createServer resolves internally.","Call server.close() on the previous server before creating a new one — and still pass a freshly resolved config.","If you must reuse config, deep-clone it before each createServer call so usedConfigs sees a different object."],"exampleFix":"// before\nconst config = await resolveConfig({}, 'serve')\nconst s1 = await createServer(config)\nconst s2 = await createServer(config) // throws\n\n// after\nconst s1 = await createServer({})\nconst s2 = await createServer({})","handlingStrategy":"validation","validationCode":"import { isResolvedConfig, type InlineConfig } from 'vite'\nfunction assertConfigUsable(config: unknown) {\n  // pass InlineConfig to createServer; never reuse a ResolvedConfig across servers.\n  if (isResolvedConfig(config)) {\n    throw new Error('Pass an InlineConfig to createServer, or re-resolve for a fresh object')\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass InlineConfig to createServer and let Vite resolve it per server.","Call server.close() and re-resolve config before starting a new server.","Never cache a ResolvedConfig across multiple createServer calls."],"tags":["dev-server","config","lifecycle","singleton"],"analyzedSha":"89620f09afcfef6b35e7bb8660132ab5b4d0cd3b","analyzedAt":"2026-08-03T19:28:02.920Z","schemaVersion":2}