{"record":{"id":"2d50f13e90d7f6ee","repo":"vitest-dev/vitest","slug":"invalid-export-in-globalsetup-file-file-exp","errorCode":null,"errorMessage":"invalid export in globalSetup file ${file}: ${exp} must be a function","messagePattern":"invalid export in globalSetup file (.+?): (.+?) must be a function","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/globalSetup.ts","lineNumber":28,"sourceCode":"\nexport async function loadGlobalSetupFiles(\n  runner: ModuleRunner,\n  globalSetup: string | string[],\n): Promise<GlobalSetupFile[]> {\n  const globalSetupFiles = toArray(globalSetup)\n  return Promise.all(\n    globalSetupFiles.map(file => loadGlobalSetupFile(file, runner)),\n  )\n}\n\nasync function loadGlobalSetupFile(\n  file: string,\n  runner: ModuleRunner,\n): Promise<GlobalSetupFile> {\n  const m = await runner.import(file)\n  for (const exp of ['default', 'setup', 'teardown']) {\n    if (m[exp] != null && typeof m[exp] !== 'function') {\n      throw new Error(\n        `invalid export in globalSetup file ${file}: ${exp} must be a function`,\n      )\n    }\n  }\n  if (m.default) {\n    return {\n      file,\n      setup: m.default,\n    }\n  }\n  else if (m.setup || m.teardown) {\n    return {\n      file,\n      setup: m.setup,\n      teardown: m.teardown,\n    }\n  }\n  else {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/node/globalSetup.ts#L10-L46","documentation":"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.","triggerScenarios":"A globalSetup file exporting default/setup/teardown as a non-function value (number, object, string, array). For example `export const setup = { foo: 1 }`.","commonSituations":"Mistyped export; named-export collision; default-exporting a config object instead of a function; refactor that changed an export's shape.","solutions":["Make the export a function: `export function setup() { ... }` or `export default function() { ... }`.","Remove the export if it wasn't meant to be a setup/teardown hook.","Check for naming collisions where setup/teardown is shadowed by a constant."],"exampleFix":"// before\nexport const setup = { init: () => db.connect() }\n\n// after\nexport function setup() {\n  db.connect()\n}","handlingStrategy":"type-guard","validationCode":"function exportsAreFunctions(mod, keys = ['default', 'setup', 'teardown']) {\n  return keys.every(k => mod[k] == null || typeof mod[k] === 'function')\n}","typeGuard":"function isFunctionExport(mod, key): boolean {\n  return mod[key] == null || typeof mod[key] === 'function'\n}","tryCatchPattern":null,"preventionTips":["Keep globalSetup exports as functions only.","Lint globalSetup files to reject non-function named exports for setup/teardown/default.","Avoid name collisions between constants and the setup/teardown hooks."],"tags":["global-setup","exports","type-validation"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}