vitest-dev/vitest · error · Error

Cannot set serialized manual mock. Define a factory function

Error message

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

What it means

Manual mocks carry a JS factory closure that cannot be represented in JSON, so the registry refuses to rehydrate a serialized `{ type: 'manual' }` payload. To restore one you must supply the factory yourself via `ManualMockedModule.fromJSON(data, factory)` (or the positional register overload).

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 d568f8ce37)

Solutions

  1. Reconstruct with an explicit factory: `const m = ManualMockedModule.fromJSON(data, () => ({ default: stub })); registry.add(m)`.
  2. Or register via the positional overload: `registry.register('manual', data.raw, data.id, data.url, factory)`.
  3. Do not attempt to round-trip manual mocks through JSON; transfer only their identity and rebuild the factory on the receiver.

Example fix

// before (fails — no factory)
registry.register({ type: 'manual', raw, id, url })

// after
registry.register('manual', data.raw, data.id, data.url, () => ({
  default: vi.fn(),
}))
Defensive patterns

Strategy: validation

Validate before calling

function registerManual(registry: any, data: any, factory: () => unknown) {
  if (data?.type === 'manual' && typeof factory !== 'function') {
    throw new Error('Manual mocks require a factory; cannot restore from JSON alone.')
  }
  if (data?.type === 'manual') {
    registry.add(
      ManualMockedModule.fromJSON(data, factory),
    )
  } else {
    registry.register(data)
  }
}

Prevention

When it happens

Trigger: Calling `registry.register({ type: 'manual', raw, id, url })` — the serialized form of a manual mock — without providing a factory function.

Common situations: Worker-thread mock sync where the main thread registered manual mocks; replaying serialized mock state; serializing a mock graph to disk and loading it back.

Related errors


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