vitest-dev/vitest · error · Error

Cannot set serialized manual mock. Define a factory…

Error message

Cannot set serialized manual mock. Define a factory function manually with `ManualMockedModule.fromJSON()`.

What it means

Thrown by `MockerRegistry.register` (object-form) when `event.type === 'manual'`. Manual mocks carry a factory function, which cannot be serialized to JSON, so there is no way to reconstruct a `ManualMockedModule` from a plain object alone. The caller must instead use the multi-argument overload that supplies the factory function directly.

Solutions

  1. Use the multi-argument overload `register('manual', raw, id, url, factory)` to supply the factory function.
  2. If deserializing, call `ManualMockedModule.fromJSON(data, factory)` and then `registry.add(module)`.
  3. Ensure the transport layer reattaches the factory before registration rather than sending a bare JSON payload.

Example fix

// before — object path cannot carry a factory
registry.register({ type: 'manual', raw, id, url })
// after — multi-arg overload with factory
registry.register('manual', raw, id, url, () => ({ fn: vi.fn() }))
Defensive patterns

Strategy: validation

Validate before calling

// Never send a manual mock through the object path; route it to the multi-arg overload.
function registerMock(registry: MockerRegistry, event: any) {
  if (event.type === 'manual') {
    throw new Error('Manual mocks must use the multi-arg register overload with a factory.')
  }
  return registry.register(event)
}

Type guard

function isManualSerializedEvent(event: unknown): boolean {
  return typeof event === 'object' && event !== null && (event as any).type === 'manual'
}

Prevention

When it happens

Trigger: A serialized manual-mock event arrives at `register` via the object path — e.g., an RPC message or IPC payload with `{ type: 'manual', ... }` and no accompanying factory. This happens when browser↔node mock coordination tries to round-trip a manual mock through JSON without reattaching the factory.

Common situations: Forking the mocker transport; a Vitest internal regression that routes manual mocks through the serialization path; custom interceptors that forward events verbatim.

Related errors


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

Appendix: source

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

        )
      }
      if (event.type === 'automock') {
        const module = AutomockedModule.fromJSON(event)
        this.add(module)
        return module
      }
      else if (event.type === 'autospy') {
        const module = AutospiedModule.fromJSON(event)
        this.add(module)
        return module
      }
      else if (event.type === 'redirect') {
        const module = RedirectedModule.fromJSON(event)
        this.add(module)
        return module
      }
      else if (event.type === 'manual') {
        throw new Error(`Cannot set serialized manual mock. Define a factory function manually with \`ManualMockedModule.fromJSON()\`.`)
      }
      else {
        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.')
    }

View on GitHub (pinned to 1fa9837ec2)