{"record":{"id":"13d5ade8b903fc4e","repo":"vitest-dev/vitest","slug":"vitest-manual-mocks-require-a-factory-function","errorCode":null,"errorMessage":"[vitest] Manual mocks require a factory function.","messagePattern":"\\[vitest\\] Manual mocks require a factory function\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/mocker/src/registry.ts","lineNumber":108,"sourceCode":"        throw new Error(`Unknown mock type: ${(event as any).type}`)\n      }\n    }\n\n    if (typeof raw !== 'string') {\n      throw new TypeError('[vitest] Mocks require a raw string.')\n    }\n\n    if (typeof url !== 'string') {\n      throw new TypeError('[vitest] Mocks require a url string.')\n    }\n\n    if (typeof id !== 'string') {\n      throw new TypeError('[vitest] Mocks require an id string.')\n    }\n\n    if (type === 'manual') {\n      if (typeof factoryOrRedirect !== 'function') {\n        throw new TypeError('[vitest] Manual mocks require a factory function.')\n      }\n      const mock = new ManualMockedModule(raw, id, url, factoryOrRedirect)\n      this.add(mock)\n      return mock\n    }\n    else if (type === 'automock' || type === 'autospy') {\n      const mock = type === 'automock'\n        ? new AutomockedModule(raw, id, url)\n        : new AutospiedModule(raw, id, url)\n      this.add(mock)\n      return mock\n    }\n    else if (type === 'redirect') {\n      if (typeof factoryOrRedirect !== 'string') {\n        throw new TypeError('[vitest] Redirect mocks require a redirect string.')\n      }\n      const mock = new RedirectedModule(raw, id, url, factoryOrRedirect)\n      this.add(mock)","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/mocker/src/registry.ts#L90-L126","documentation":"Thrown by MockRegistry.register when a mock of type 'manual' is registered without a factory function. Manual mocks (vi.mock with a factory) must supply a function that returns the mock module object; without it the registry cannot construct the ManualMockedModule. The guard runs after raw/url/id string validation, so it specifically rejects a non-function factoryOrRedirect for the manual branch.","triggerScenarios":"Calling vi.mock('path', factory) where factory is undefined, null, a string, or any non-function value; or directly invoking registry.register({ type: 'manual', raw, id, url }, factoryOrRedirect) with a non-function. Also triggered by a hoisted vi.mock whose factory reference was not yet defined (TDZ/undefined).","commonSituations":"Forgetting the second argument to vi.mock; referencing a factory declared with const/let (hoisting strips it because vi.mock is hoisted to top of file); copy-paste from vi.doMock that omitted the factory; passing a mock object directly instead of a function returning it.","solutions":[],"exampleFix":"// before\nvi.mock('./config', { provide: 'value' })\n// after\nvi.mock('./config', () => ({ provide: 'value' }))","handlingStrategy":"validation","validationCode":"// Before calling vi.mock, ensure the factory is a function\nfunction isMockFactory(v: unknown): v is () => unknown {\n  return typeof v === 'function'\n}\nif (!isMockFactory(factory)) throw new Error('factory must be a function')\nvi.mock(path, factory)","typeGuard":"function isMockFactory(v: unknown): v is () => unknown { return typeof v === 'function' }","tryCatchPattern":null,"preventionTips":["Always pass an arrow function returning an object to vi.mock","Use vi.hoisted() for any values referenced inside the factory","Lint for vi.mock calls missing a second function argument"],"tags":["vitest","mocker","vi-mock","configuration"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}