vitest-dev/vitest · error · TypeError
invalid return value in globalSetup file
Error message
invalid return value in globalSetup file ${globalSetupFile.file}. Must return a function What it means
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.
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.
Example fix
// before
export function setup() {
return { cleanup() {} } // object, not a function
}
// after
export function setup() {
return function cleanup() {}
}
// or export teardown explicitly
export function teardown() {} Defensive patterns
Strategy: validation
Validate before calling
// Validate globalSetup return shape during development.
function validateGlobalSetupReturn(ret: unknown) {
if (ret != null && typeof ret !== 'function') {
throw new TypeError('globalSetup setup must return undefined or a function, got ' + typeof ret)
}
} Type guard
const isTeardownOrAbsent = (ret: unknown): ret is undefined | (() => unknown | Promise<unknown>) => ret == null || typeof ret === 'function'
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cannot import " ": the test context was torn down.
- Vitest failed to access its internal state. One of the…
- [vitest] The provider was closed.
- Access denied to " ". See Vite config documentation for…
- All browser instances within a project must use the same…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/55197931c5037f75.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/node/project.ts:241
/** @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 1fa9837ec2)