vitest-dev/vitest · error · Error

Unknown mock type

Error message

Unknown mock type: ${(mock as any).type}

What it means

Thrown by the MSW-based browser module interceptor when a registered mock's `type` does not match any of the handled cases (`manual`, `automock`, `autospy`, `redirect`) in the request-handler switch. The interceptor serves mocked modules over HTTP in browser mode; reaching the `default` branch means the registry holds a mock whose type is outside the `MockedModuleType` union. This is a defensive guard that should be unreachable under normal use.

Solutions

  1. If you forked Vitest or wrote a custom interceptor, extend the switch in `interceptor-msw.ts` to handle your custom mock type.
  2. Update Vitest to the latest patch release — this branch indicates an internal inconsistency that may already be fixed.
  3. File a Vitest bug report with a minimal browser-mode reproduction, since the four union types should make this unreachable in stock Vitest.
Defensive patterns

Strategy: type-guard

Validate before calling

// Before adding a mock to the MSW interceptor, confirm its type is one the handler switch covers.
const HANDLED_MOCK_TYPES = new Set(['manual', 'automock', 'autospy', 'redirect'])
function isHandledMockType(mock: { type: string }): boolean {
  return HANDLED_MOCK_TYPES.has(mock.type)
}
if (!isHandledMockType(mock)) {
  throw new Error(`Refusing to register mock with unsupported type: ${mock.type}`)
}

Type guard

function isKnownMockType(mock: unknown): mock is { type: 'manual' | 'automock' | 'autospy' | 'redirect' } {
  return typeof mock === 'object' && mock !== null
    && typeof (mock as any).type === 'string'
    && ['manual', 'automock', 'autospy', 'redirect'].includes((mock as any).type)
}

Prevention

When it happens

Trigger: A mock object with an unexpected `type` string is stored in the `ModuleMockerMSWInterceptor.mocks` registry and then served by the `http.get(/.+/)` handler. This can happen if a custom/forked interceptor registers a non-standard mock class, or if the registry is corrupted by a race during concurrent `register()`/`invalidate()` calls.

Common situations: Running Vitest browser mode with a forked or patched mocker that introduces a new mock type without extending the switch; concurrent test file teardown that mutates the registry while a request is in flight; a Vitest internal regression after adding a new `MockedModuleType` without updating the interceptor.

Related errors


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

Appendix: source

Thrown at packages/mocker/src/browser/interceptor-msw.ts:109

      const worker = setupWorker(
        http.get(/.+/, async ({ request }) => {
          const path = cleanQuery(request.url.slice(location.origin.length))
          if (!this.mocks.has(path)) {
            return passthrough()
          }

          const mock = this.mocks.get(path)!

          switch (mock.type) {
            case 'manual':
              return this.resolveManualMock(mock)
            case 'automock':
            case 'autospy':
              return Response.redirect(injectQuery(path, `mock=${mock.type}`))
            case 'redirect':
              return Response.redirect(mock.redirect)
            default:
              throw new Error(`Unknown mock type: ${(mock as any).type}`)
          }
        }),
      )
      return worker.start(this.options.mswOptions).then(() => worker)
    }).finally(() => {
      this.worker = worker
      this.startPromise = undefined
    })
    return await this.startPromise
  }
}

const trailingSeparatorRE = /[?&]$/
const timestampRE = /\bt=\d{13}&?\b/
const versionRE = /\bv=\w{8}&?\b/
function cleanQuery(url: string) {
  return url.replace(timestampRE, '').replace(versionRE, '').replace(trailingSeparatorRE, '')
}

View on GitHub (pinned to 1fa9837ec2)