{"id":"7960cf0a824dcf1c","repo":"vitest-dev/vitest","slug":"runner-must-export-a-default-function-but-got-t","errorCode":null,"errorMessage":"Runner must export a default function, but got ${typeof mod.default} imported from ${config.runner}","messagePattern":"Runner must export a default function, but got (.+?) imported from (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/runtime/runners/index.ts","lineNumber":20,"sourceCode":"import type { SerializedConfig } from '../config'\nimport type { TestModuleRunner } from '../moduleRunner/testModuleRunner'\nimport type { VitestRunner, VitestRunnerConstructor } from '../runner/types'\nimport { takeCoverageInsideWorker } from '../../integrations/coverage'\nimport { rpc } from '../rpc'\nimport { loadDiffConfig, loadSnapshotSerializers } from '../setup-common'\nimport { getWorkerState } from '../utils'\nimport { TestRunner } from './test'\n\nasync function getTestRunnerConstructor(\n  config: SerializedConfig,\n  moduleRunner: TestModuleRunner,\n): Promise<VitestRunnerConstructor> {\n  if (!config.runner) {\n    return TestRunner as any as VitestRunnerConstructor\n  }\n  const mod = await moduleRunner.import(config.runner)\n  if (!mod.default && typeof mod.default !== 'function') {\n    throw new Error(\n      `Runner must export a default function, but got ${typeof mod.default} imported from ${\n        config.runner\n      }`,\n    )\n  }\n  return mod.default as VitestRunnerConstructor\n}\n\nexport async function resolveTestRunner(\n  config: SerializedConfig,\n  moduleRunner: TestModuleRunner,\n  traces: Traces,\n): Promise<VitestRunner> {\n  const TestRunner = await getTestRunnerConstructor(config, moduleRunner)\n  const testRunner = new TestRunner(config)\n\n  // inject private executor to every runner\n  Object.defineProperty(testRunner, 'moduleRunner', {","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/runtime/runners/index.ts#L2-L38","documentation":"Thrown by getTestRunnerConstructor when a custom runner is configured (`config.runner` points to a module path) but the imported module has no `default` export that is usable as a constructor. Vitest needs `export default class MyRunner ...` (or a function) so it can do `new TestRunner(config)`. The message reports the actual typeof value it received so you can see what shape the module exported.","triggerScenarios":"Setting `test.runner: './my-runner.js'` where that file only has named exports, no default export. Exporting default as an object or a plain value instead of a class/function. Forgetting to add `export default` to the runner file.","commonSituations":"Writing a custom VitestRunner for the first time and omitting the default export. Refactoring a runner from default to named export. Pointing config.runner at the wrong file that happens to export something else.","solutions":["Add `export default` to the runner module and make it a class or function: `export default class MyRunner extends VitestRunner { ... }`.","Verify the path in `config.runner` resolves to the intended file.","If using TypeScript, make sure the build emits a usable default export.","Extend the VitestRunner base type from the runtime types so the shape is correct."],"exampleFix":"// before (./my-runner.js)\nexport class MyRunner { /* ... */ }\n\n// after\nimport { VitestRunner } from 'vitest/runners'\nexport default class MyRunner extends VitestRunner {\n  importFile(file) { /* ... */ }\n}","handlingStrategy":"type-guard","validationCode":"// Verify your runner module before pointing config at it\nimport * as runnerMod from './my-runner.js'\nif (typeof runnerMod.default !== 'function') {\n  throw new Error('runner module must export a default class/function')\n}","typeGuard":"import type { VitestRunnerConstructor } from 'vitest'\nfunction isRunnerCtor(mod: any): mod is { default: VitestRunnerConstructor } {\n  return mod && typeof mod.default === 'function'\n}","tryCatchPattern":null,"preventionTips":["Always `export default class ... extends VitestRunner`.","Keep a unit test that imports your runner and asserts typeof default === 'function'.","Point config.runner at the built output, not a stale source path."],"tags":["config","runner","esm"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}