vitejs/vite · error · Error

external must be an array

Error message

external must be an array

What it means

Thrown by the externalizeDepsInWatchPlugin in Vite's own rolldown build config when running in watch mode. The plugin attempts to concatenate devDependencies onto options.external, but Rollup/Rolldown allows external to be a function (not just an array). If the resolved config's external is a function or a non-array value, this assertion fires. This error is internal to building Vite itself, not consumer application builds.

Source

Thrown at packages/vite/rolldown.config.ts:215

          "export * from '../../src/node/index.ts'",
        )
        writeFileSync(
          'dist/node/module-runner.d.ts',
          "export * from '../../src/module-runner/index.ts'",
        )
      }
    },
  }
}

function externalizeDepsInWatchPlugin(): Plugin {
  return {
    name: 'externalize-deps-in-watch',
    options(options) {
      if (this.meta.watchMode) {
        options.external ||= []
        if (!Array.isArray(options.external))
          throw new Error('external must be an array')
        options.external = options.external.concat(
          Object.keys(pkg.devDependencies),
        )
      }
    },
  }
}

interface ShimOptions {
  src?: string
  replacement: string
  pattern?: RegExp
}

function shimDepsPlugin(deps: Record<string, ShimOptions[]>): Plugin {
  const transformed: Record<string, boolean> = {}

  return {

View on GitHub (pinned to 89620f09af)

Solutions

  1. If you modified nodeConfig.external to a function, convert the externalizeDepsInWatchPlugin logic to handle function externals (wrap the function).
  2. Keep options.external as an array in the base config; the watch-mode plugin only supports arrays.
  3. If you hit this without modifying Vite's source, ensure you're using the correct build scripts.

Example fix

// before — external is a function
external: (id) => id.includes('node:')
// after — the watch plugin needs an array; wrap instead
const baseExternal = [...Object.keys(pkg.dependencies)]
external: [
  ...baseExternal,
  // add function-based externals as regex patterns instead
]
Defensive patterns

Strategy: validation

Validate before calling

// For Vite contributors: validate external is an array before watch-mode concatenation
function ensureArrayExternal(options) {
  if (options.external && !Array.isArray(options.external)) {
    throw new TypeError('options.external must be an array for watch-mode devDependencies injection')
  }
}

Type guard

function isArrayExternal(external: unknown): external is string[] | RegExp[] {
  return Array.isArray(external)
}

Try / catch

// In the plugin, handle function externals gracefully
if (!Array.isArray(options.external)) {
  if (typeof options.external === 'function') {
    const fn = options.external
    const deps = Object.keys(pkg.devDependencies)
    options.external = (id) => fn(id) || deps.includes(id)
  } else {
    throw new Error('external must be an array')
  }
}

Prevention

When it happens

Trigger: Running Vite's own build in watch mode (e.g., pnpm dev or the rolldown build with --watch) when the nodeConfig's external field has been changed from an array to a function or another type by a code change in rolldown.config.ts.

Common situations: A contributor to Vite's codebase modifies the external field in nodeConfig to use a function for more sophisticated externals resolution, then runs the dev/watch build. This is a development-time error for Vite contributors, not end users.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/50c9e15bb7c2cdee.json. Report an issue: GitHub.