vitest-dev/vitest · error · TypeError

[vitest] Manual mocks require a factory function.

Error message

[vitest] Manual mocks require a factory function.

What it means

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.

Example fix

// before
vi.mock('./config', { provide: 'value' })
// after
vi.mock('./config', () => ({ provide: 'value' }))
Defensive patterns

Strategy: validation

Validate before calling

// Before calling vi.mock, ensure the factory is a function
function isMockFactory(v: unknown): v is () => unknown {
  return typeof v === 'function'
}
if (!isMockFactory(factory)) throw new Error('factory must be a function')
vi.mock(path, factory)

Type guard

function isMockFactory(v: unknown): v is () => unknown { return typeof v === 'function' }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/13d5ade8b903fc4e. Report an issue: GitHub.

Appendix: source

Thrown at packages/mocker/src/registry.ts:108

        throw new Error(`Unknown mock type: ${(event as any).type}`)
      }
    }

    if (typeof raw !== 'string') {
      throw new TypeError('[vitest] Mocks require a raw string.')
    }

    if (typeof url !== 'string') {
      throw new TypeError('[vitest] Mocks require a url string.')
    }

    if (typeof id !== 'string') {
      throw new TypeError('[vitest] Mocks require an id string.')
    }

    if (type === 'manual') {
      if (typeof factoryOrRedirect !== 'function') {
        throw new TypeError('[vitest] Manual mocks require a factory function.')
      }
      const mock = new ManualMockedModule(raw, id, url, factoryOrRedirect)
      this.add(mock)
      return mock
    }
    else if (type === 'automock' || type === 'autospy') {
      const mock = type === 'automock'
        ? new AutomockedModule(raw, id, url)
        : new AutospiedModule(raw, id, url)
      this.add(mock)
      return mock
    }
    else if (type === 'redirect') {
      if (typeof factoryOrRedirect !== 'string') {
        throw new TypeError('[vitest] Redirect mocks require a redirect string.')
      }
      const mock = new RedirectedModule(raw, id, url, factoryOrRedirect)
      this.add(mock)

View on GitHub (pinned to 1fa9837ec2)