{"id":"55197931c5037f75","repo":"vitest-dev/vitest","slug":"invalid-return-value-in-globalsetup-file-globals","errorCode":null,"errorMessage":"invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function","messagePattern":"invalid return value in globalSetup file (.+?)\\. Must return a function","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/project.ts","lineNumber":232,"sourceCode":"\n  /** @internal */\n  async _initializeGlobalSetup() {\n    if (this._globalSetups) {\n      return\n    }\n\n    this._globalSetups = await loadGlobalSetupFiles(\n      this.runner,\n      this.config.globalSetup,\n    )\n\n    for (const globalSetupFile of this._globalSetups) {\n      const teardown = await globalSetupFile.setup?.(this)\n      if (teardown == null || !!globalSetupFile.teardown) {\n        continue\n      }\n      if (typeof teardown !== 'function') {\n        throw new TypeError(\n          `invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`,\n        )\n      }\n      globalSetupFile.teardown = teardown\n    }\n  }\n\n  onTestsRerun(cb: OnTestsRerunHandler): void {\n    this.vitest.onTestsRerun(cb)\n  }\n\n  /** @internal */\n  async _teardownGlobalSetup(): Promise<void> {\n    if (!this._globalSetups) {\n      return\n    }\n    for (const globalSetupFile of [...this._globalSetups].reverse()) {\n      await globalSetupFile.teardown?.()","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/project.ts#L214-L250","documentation":"A globalSetup file may return a teardown function that Vitest calls after the whole run. In project.ts:226-237 Vitest calls setup(this); if the returned value is not null/undefined and the module did not already export a named teardown, then the returned value MUST be a function. Returning any other type (object, string, number, array) is rejected because Vitest cannot invoke it as a teardown.","triggerScenarios":"A globalSetup file whose default/named setup returns an object (e.g. an API client or a state holder), a string, a number, or a Promise resolving to a non-function, while also not exporting a teardown function.","commonSituations":"Returning a cleanup descriptor object like { cleanup: () => {} } instead of the function directly; returning a DB handle you intend to close later; forgetting that an async setup returns the value of the last awaited expression which isn't a function.","solutions":["Return either undefined/nothing or a single function from setup: return async () => { await db.close() }.","If you need to return structured data, export a named teardown function from the same module instead of returning from setup.","Make sure an async setup's last statement / return value is the teardown function, not a data object."],"exampleFix":"// before\nexport default function setup(project) {\n  const client = createClient()\n  return { client } // object, not a function\n}\n\n// after\nexport default function setup(project) {\n  const client = createClient()\n  return async () => { await client.close() }\n}","handlingStrategy":"validation","validationCode":"const teardown = await setupModule.setup?.(project)\nif (teardown != null && typeof teardown !== 'function' && !setupModule.teardown) {\n  throw new TypeError(`globalSetup '${file}' must return a function, got ${typeof teardown}`)\n}","typeGuard":"function isTeardownFn(v: unknown): v is (() => unknown) | undefined | null {\n  return v == null || typeof v === 'function'\n}","tryCatchPattern":null,"preventionTips":["Keep globalSetup files tiny: do setup, return one async teardown function.","If returning data, export a named teardown instead.","Lint globalSetup files to forbid returning object literals from setup."],"tags":["global-setup","teardown","lifecycle","configuration"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}