vitest-dev/vitest · error

invalid export in globalSetup file

Error message

invalid export in globalSetup file ${file}: ${exp} must be a function

What it means

loadGlobalSetupFile requires each of default/setup/teardown exports to be a function IF present (non-null). If an export is non-null but not a function (a constant, object, number), it throws. This enforces the globalSetup callable contract before invocation.

Solutions

  1. Make the export a function: `export function setup() { ... }` or `export default function() { ... }`.
  2. Remove the export if it wasn't meant to be a setup/teardown hook.
  3. Check for naming collisions where setup/teardown is shadowed by a constant.

Example fix

// before
export const setup = { init: () => db.connect() }

// after
export function setup() {
  db.connect()
}
Defensive patterns

Strategy: type-guard

Validate before calling

function exportsAreFunctions(mod, keys = ['default', 'setup', 'teardown']) {
  return keys.every(k => mod[k] == null || typeof mod[k] === 'function')
}

Type guard

function isFunctionExport(mod, key): boolean {
  return mod[key] == null || typeof mod[key] === 'function'
}

Prevention

When it happens

Trigger: A globalSetup file exporting default/setup/teardown as a non-function value (number, object, string, array). For example `export const setup = { foo: 1 }`.

Common situations: Mistyped export; named-export collision; default-exporting a config object instead of a function; refactor that changed an export's shape.

Related errors


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

Appendix: source

Thrown at packages/vitest/src/node/globalSetup.ts:28

export async function loadGlobalSetupFiles(
  runner: ModuleRunner,
  globalSetup: string | string[],
): Promise<GlobalSetupFile[]> {
  const globalSetupFiles = toArray(globalSetup)
  return Promise.all(
    globalSetupFiles.map(file => loadGlobalSetupFile(file, runner)),
  )
}

async function loadGlobalSetupFile(
  file: string,
  runner: ModuleRunner,
): Promise<GlobalSetupFile> {
  const m = await runner.import(file)
  for (const exp of ['default', 'setup', 'teardown']) {
    if (m[exp] != null && typeof m[exp] !== 'function') {
      throw new Error(
        `invalid export in globalSetup file ${file}: ${exp} must be a function`,
      )
    }
  }
  if (m.default) {
    return {
      file,
      setup: m.default,
    }
  }
  else if (m.setup || m.teardown) {
    return {
      file,
      setup: m.setup,
      teardown: m.teardown,
    }
  }
  else {

View on GitHub (pinned to 1fa9837ec2)