vitest-dev/vitest · error · Error

Test function is not found. Did you add it using `setFn`?

Error message

Test function is not found. Did you add it using `setFn`?

What it means

During `runTest` (run.ts:647-652), if the runner has no custom `runTask`, Vitest fetches the test's function via `getFn(test)`. If no function was registered for the task (via `setFn`), it throws this error pointing to `setFn`. This indicates the task was collected without an executable body — typically a setup/registration bug rather than a user test error.

Source

Thrown at packages/vitest/src/runtime/runner/run.ts:649

          })

          test.result!.repeatCount = repeatCount

          beforeEachCleanups = await $('test.beforeEach', () => callSuiteHook(
            suite,
            test,
            'beforeEach',
            runner,
            [test.context, suite],
          ))

          if (runner.runTask) {
            await $('test.callback', () => limitMaxConcurrency(() => runner.runTask!(test)))
          }
          else {
            const fn = getFn(test)
            if (!fn) {
              throw new Error(
                'Test function is not found. Did you add it using `setFn`?',
              )
            }
            await $('test.callback', () => limitMaxConcurrency(() => fn()))
          }

          await runner.onAfterTryTask?.(test, {
            retry: retryCount,
            repeats: repeatCount,
          })

          if (test.result!.state !== 'fail') {
            test.result!.state = 'pass'
          }
        }
        catch (e) {
          failTask(test.result!, e, runner.config._diffOptions)
        }

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Ensure `setFn(task, fn)` is called for every test task before it runs.
  2. Use the standard `test(...)` API which registers the function automatically.
  3. If using a custom runner, implement `runner.runTask` or guarantee `setFn` is invoked during collection.

Example fix

// before: custom task without function
const task = createTestTask()
await runTest(task, runner) // getFn returns undefined
// after
setFn(task, () => { /* test body */ })
await runTest(task, runner)
Defensive patterns

Strategy: validation

Validate before calling

// Custom runner: ensure setFn is called for every task.
import { setFn } from 'vitest/runtime'
function ensureFn(task: Test) {
  if (typeof (task as any).fn !== 'function') {
    setFn(task, () => { throw new Error(`No body for ${task.name}`) })
  }
}

Prevention

When it happens

Trigger: A custom runner or plugin that creates a `Test` task and calls `runTest` without first registering a function via `setFn`; manually constructing tasks; a collection path that skips `setFn` assignment.

Common situations: Custom Vitest runner implementations; programmatic test creation; bugs in test-collection middleware; running a `todo` task that has no body but reached execution.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/997ee2934cd76e77.json. Report an issue: GitHub.