{"record":{"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":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/project.ts","lineNumber":241,"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":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/node/project.ts#L223-L259","documentation":"When loading globalSetup files, Vitest calls each setup function and, if the file does not export its own teardown, treats the setup return value as the teardown. If that return value is non-null but not a function, Vitest throws a TypeError because it cannot call it later as a teardown.","triggerScenarios":"A globalSetup file's setup() returns a truthy non-function (e.g. an object, a Promise resolving to an object, a number) and the file does not export an explicit teardown.","commonSituations":"Refactoring a globalSetup to return a cleanup object instead of a function, forgetting that async setup returning a non-function value triggers this, or copy-paste from a setup that returned a closure.","solutions":["Return either nothing (undefined/null) or a function from globalSetup setup.","If you need richer teardown, export an explicit teardown export from the globalSetup file instead.","Ensure async setup resolves to a function (or undefined), not an object."],"exampleFix":"// before\nexport function setup() {\n  return { cleanup() {} } // object, not a function\n}\n// after\nexport function setup() {\n  return function cleanup() {}\n}\n// or export teardown explicitly\nexport function teardown() {}","handlingStrategy":"validation","validationCode":"// Validate globalSetup return shape during development.\nfunction validateGlobalSetupReturn(ret: unknown) {\n  if (ret != null && typeof ret !== 'function') {\n  throw new TypeError('globalSetup setup must return undefined or a function, got ' + typeof ret)\n  }\n}","typeGuard":"const isTeardownOrAbsent = (ret: unknown): ret is undefined | (() => unknown | Promise<unknown>) =>\n  ret == null || typeof ret === 'function'","tryCatchPattern":null,"preventionTips":["Return only undefined or a teardown function from globalSetup setup.","Prefer exporting an explicit teardown export for complex cleanup.","For async setup, ensure the resolved value is a function or undefined."],"tags":["globalsetup","lifecycle","config","teardown"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}