vitest-dev/vitest · error · TypeError
invalid return value in globalSetup file ${globalSetupFile.f
Error message
invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function What it means
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.
Source
Thrown at packages/vitest/src/node/project.ts:232
/** @internal */
async _initializeGlobalSetup() {
if (this._globalSetups) {
return
}
this._globalSetups = await loadGlobalSetupFiles(
this.runner,
this.config.globalSetup,
)
for (const globalSetupFile of this._globalSetups) {
const teardown = await globalSetupFile.setup?.(this)
if (teardown == null || !!globalSetupFile.teardown) {
continue
}
if (typeof teardown !== 'function') {
throw new TypeError(
`invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function`,
)
}
globalSetupFile.teardown = teardown
}
}
onTestsRerun(cb: OnTestsRerunHandler): void {
this.vitest.onTestsRerun(cb)
}
/** @internal */
async _teardownGlobalSetup(): Promise<void> {
if (!this._globalSetups) {
return
}
for (const globalSetupFile of [...this._globalSetups].reverse()) {
await globalSetupFile.teardown?.()View on GitHub (pinned to d568f8ce37)
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.
Example fix
// before
export default function setup(project) {
const client = createClient()
return { client } // object, not a function
}
// after
export default function setup(project) {
const client = createClient()
return async () => { await client.close() }
} Defensive patterns
Strategy: validation
Validate before calling
const teardown = await setupModule.setup?.(project)
if (teardown != null && typeof teardown !== 'function' && !setupModule.teardown) {
throw new TypeError(`globalSetup '${file}' must return a function, got ${typeof teardown}`)
} Type guard
function isTeardownFn(v: unknown): v is (() => unknown) | undefined | null {
return v == null || typeof v === 'function'
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- [vitest] The provider was closed.
- Page "${sessionId}" not found in ${this.browserName} browser
- Browser is not initialized
- Cannot find iframe with id ${event.iframeId}
- Cannot take a screenshot outside of a test.
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/55197931c5037f75.json.
Report an issue: GitHub.