vitest-dev/vitest · critical · Error

Cannot spawn child server without a parent dev server.

Error message

Cannot spawn child server without a parent dev server.

What it means

ProjectParentBrowser.spawn clones itself into a child ProjectBrowser tied to a TestProject, and the clone needs the parent's Vite dev server (this.vite) to resolve modules. setServer() is what assigns that server; if spawn() is called before setServer(), there is nothing to clone from and the error fires.

Solutions

  1. If you are a plugin author, defer spawn() to a server-ready hook (e.g. after configureServer resolves) so setServer has run.
  2. Ensure no code path constructs a TestProject and immediately spawns its browser before the parent server is registered.
  3. On stock Vitest, upgrade to a version where plugin ordering is correct and report a bug with a reproduction if it persists.

Example fix

// before
const child = parent.spawn(project) // parent.vite not yet set
// after
parent.setServer(viteDevServer)
const child = parent.spawn(project)
Defensive patterns

Strategy: validation

Validate before calling

function parentServerReady(parent: { vite?: unknown }): boolean {
  return !!parent.vite
}

Prevention

When it happens

Trigger: Calling projectParent.spawn(project) before the parent's setServer(viteDevServer) hook has run. Typically an internal ordering bug in the browser plugin lifecycle, or a custom integration that drives spawn manually.

Common situations: A plugin that constructs a TestProject and calls spawn() during configureServer before the parent server reference is stored; a regression in plugin ordering after upgrading Vite/Vitest; a test harness that mocks parts of the lifecycle.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/ad0a0ccd8a3f2031. Report an issue: GitHub.

Appendix: source

Thrown at packages/browser/src/node/projectParent.ts:158

      resolve(distRoot, 'client/esm-client-injector.js'),
      'utf8',
    ).then(js => (this.injectorJs = js))
    this.errorCatcherUrl = join('/@fs/', resolve(distRoot, 'client/error-catcher.js'))

    this.matchersUrl = join('/@fs/', distRoot, 'expect-element.js')
    this.stateJs = readFile(
      resolve(distRoot, 'state.js'),
      'utf-8',
    ).then(js => (this.stateJs = js))
  }

  public setServer(vite: Vite.ViteDevServer): void {
    this.vite = vite
  }

  public spawn(project: TestProject): ProjectBrowser {
    if (!this.vite) {
      throw new Error(`Cannot spawn child server without a parent dev server.`)
    }
    const clone = new ProjectBrowser(
      this,
      project,
      '/',
    )
    this.children.add(clone)
    return clone
  }

  public parseErrorStacktrace(
    e: TestError,
    options: StackTraceParserOptions = {},
  ): ParsedStack[] {
    return parseErrorStacktrace(e, {
      ...this.stackTraceOptions,
      ...options,
    })

View on GitHub (pinned to 1fa9837ec2)