vitest-dev/vitest · error · TypeError

vi.doMock() expects a string path, but received a ${typeof p

Error message

vi.doMock() expects a string path, but received a ${typeof path}

What it means

Thrown by vi.doMock() when its first argument is not a string. The method's TypeScript signature accepts `string | Promise<unknown>` only to keep the compiler happy for dynamic-import-style call sites, but at runtime the mocker needs a resolvable module specifier string. Receiving anything else (undefined, an object, a number) means the call cannot queue a mock and Vitest fails fast with a TypeError rather than silently no-oping.

Source

Thrown at packages/vitest/src/integrations/vi.ts:680

                  _mocker().getMockContext().callstack,
                ),
              )
          : factory,
      )
    },

    unmock(path: string | Promise<unknown>) {
      if (typeof path !== 'string') {
        throw new TypeError(
          `vi.unmock() expects a string path, but received a ${typeof path}`,
        )
      }
      _mocker().queueUnmock(path, getImporter('unmock'))
    },

    doMock(path: string | Promise<unknown>, factory?: MockOptions | MockFactoryWithHelper) {
      if (typeof path !== 'string') {
        throw new TypeError(
          `vi.doMock() expects a string path, but received a ${typeof path}`,
        )
      }
      const importer = getImporter('doMock')
      _mocker().queueMock(
        path,
        importer,
        typeof factory === 'function'
          ? () =>
              factory(() =>
                _mocker().importActual(
                  path,
                  importer,
                  _mocker().getMockContext().callstack,
                ),
              )
          : factory,
      )

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Pass a string module specifier: vi.doMock('./path/to/module', factory).
  2. If the path comes from a variable, add a runtime check `if (typeof p === 'string')` or assert it before calling doMock.
  3. Enable strict TypeScript checking on the call site so non-string values are caught at compile time (note the signature is intentionally permissive, so also rely on code review).
  4. If you intended to pass a Promise from import(), await it or use the string literal directly — doMock does not accept awaited modules either.

Example fix

// before
const mod = await import('./lib')
vi.doMock(mod)
// after
vi.doMock('./lib', () => mockFactory)
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof path !== 'string') {
  throw new Error('doMock requires a string module path')
}
vi.doMock(path, factory)

Type guard

function isMockPath(path: unknown): path is string {
  return typeof path === 'string' && path.length > 0
}

Prevention

When it happens

Trigger: Calling vi.doMock() with a non-string first argument: vi.doMock(undefined), vi.doMock(someModuleObject), vi.doMock(42), or passing a variable whose value is undefined at runtime. Also triggered by spreading arguments incorrectly, e.g. vi.doMock(...someArray) where the first element is not a string.

Common situations: Refactoring an import and forgetting to update the literal path passed to vi.doMock; dynamically computing a module path that resolves to undefined; copy-paste from vi.mock() (which is hoisted and string-only) into a doMock call while reusing a non-string variable; TS loose typing hiding the bug because the union includes Promise<unknown>.


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