cypress-io/cypress · error · Error

${err}

Error message

${err}

What it means

The catch-all in devServer.create: it wraps the createServer/createViteDevServerConfig phase. If the thrown value is already an Error it is rethrown unchanged; any non-Error value (string, object, plain rejection) is coerced via `new Error(err as string)`. So the surfaced message is whatever non-Error value the underlying Vite/config pipeline rejected with, stringified.

Source

Thrown at npm/vite-dev-server/src/devServer.ts:119

devServer.create = async function createDevServer (devServerConfig: ViteDevServerConfig, vite: Vite_7 | Vite_8) {
  try {
    // Handling here is mainly for conditional generics to make sure we get the types correct between vite 7 and vite 8.
    // Eventually, vite 8 will be the default and we can remove this logic
    if (isVite8(vite)) {
      const config = await createViteDevServerConfig<Vite_8>(devServerConfig, vite as Vite_8)

      return await (vite as Vite_8).createServer(config)
    }

    const config = await createViteDevServerConfig<Vite_7>(devServerConfig, vite as Vite_7)

    return await (vite as Vite_7).createServer(config)
  } catch (err) {
    if (err instanceof Error) {
      throw err
    }

    throw new Error(err as string)
  }
}

View on GitHub (pinned to 0d85fdc912)

Solutions

  1. Inspect the embedded message — it is the raw stringified rejection from the Vite pipeline.
  2. Reproduce the viteConfig outside Cypress with `vite` directly to isolate whether the fault is in your config or in Cypress's wrapping.
  3. Ensure any custom Vite plugins throw real Errors (with stack traces), not strings, for diagnosable output.
  4. Align your installed Vite major (5/6/7/8) with plugin compatibility.

Example fix

// before: plugin throws a string
const myPlugin = () => ({ name: 'p', transform () { throw 'bad input' } })
// after: throw a real Error
const myPlugin = () => ({ name: 'p', transform () { throw new Error('bad input') } })
Defensive patterns

Strategy: try-catch

Type guard

const isRealError = (e: unknown): e is Error => e instanceof Error

Try / catch

try {
  await devServer.create(devServerConfig, vite)
} catch (err) {
  const e = err instanceof Error ? err : new Error(String(err))
  // log e, decide retry vs fail
  throw e
}

Prevention

When it happens

Trigger: Any failure inside vite.createServer(config) or createViteDevServerConfig — e.g. an invalid plugin, a config that throws a string, an ESM/CJS interop rejection, or a plugin that rejects with a plain object rather than an Error. The wrapper ensures Cypress always rethrows a real Error.

Common situations: A user Vite plugin that throws a string instead of an Error; a viteConfig function that returns an invalid shape; a config import that fails to resolve; version skew between installed Vite and a plugin expecting a different API.

Related errors


AI-assisted analysis of cypress-io/cypress@0d85fdc912 (2026-08-12). Data as JSON: /api/errors/b3b6dcd12ad58c09. Report an issue: GitHub.