{"record":{"id":"997ee2934cd76e77","repo":"vitest-dev/vitest","slug":"test-function-is-not-found-did-you-add-it-using","errorCode":null,"errorMessage":"Test function is not found. Did you add it using `setFn`?","messagePattern":"Test function is not found\\. Did you add it using `setFn`\\?","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/runner/run.ts","lineNumber":649,"sourceCode":"          })\n\n          test.result!.repeatCount = repeatCount\n\n          beforeEachCleanups = await $('test.beforeEach', () => callSuiteHook(\n            suite,\n            test,\n            'beforeEach',\n            runner,\n            [test.context, suite],\n          ))\n\n          if (runner.runTask) {\n            await $('test.callback', () => limitMaxConcurrency(() => runner.runTask!(test)))\n          }\n          else {\n            const fn = getFn(test)\n            if (!fn) {\n              throw new Error(\n                'Test function is not found. Did you add it using `setFn`?',\n              )\n            }\n            await $('test.callback', () => limitMaxConcurrency(() => fn()))\n          }\n\n          await runner.onAfterTryTask?.(test, {\n            retry: retryCount,\n            repeats: repeatCount,\n          })\n\n          if (test.result!.state !== 'fail') {\n            test.result!.state = 'pass'\n          }\n        }\n        catch (e) {\n          failTask(test.result!, e, runner.config._diffOptions)\n        }","sourceCodeStart":631,"sourceCodeEnd":667,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/vitest/src/runtime/runner/run.ts#L631-L667","documentation":"Thrown during test execution when the test task has no callable function attached and the runner does not provide a custom runTask. Every test must have its function registered via setFn during collection; a missing fn usually means the test was registered in a way that skipped function assignment. This is almost always an internal/collector bug rather than a user typo.","triggerScenarios":"A custom runner/collector that creates a test task without calling setFn; programmatically constructing tasks and forgetting the function; a plugin that intercepts test registration and drops the fn.","commonSituations":"Writing a custom test API that wraps test() but fails to forward the function; using low-level collector APIs incorrectly; a broken transform that strips the test body.","solutions":["Ensure every test() call includes a function callback (not just a name).","If using custom collectors, call setFn(test, fn) explicitly after creating the task.","If you implement runner.runTask, you bypass this check; otherwise the fn is required."],"exampleFix":"// before (custom collector)\nconst t = createTest({ name: 'x' })\n// forgot to set fn\n\n// after\nsetFn(t, () => { expect(true).toBe(true) })","handlingStrategy":"validation","validationCode":"function assertTestHasFn(test: Test) {\n  if (!getFn(test)) throw new Error(`Test ${test.name} has no function`)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass a function callback to test().","In custom collectors, call setFn immediately after creating a task.","Prefer the public test/describe APIs over low-level task construction."],"tags":["runner","collector","internal"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}