{"id":"3a97f298e5989c05","repo":"vitest-dev/vitest","slug":"cannot-set-serialized-manual-mock-define-a-factor","errorCode":null,"errorMessage":"Cannot set serialized manual mock. Define a factory function manually with `ManualMockedModule.fromJSON()`.","messagePattern":"Cannot set serialized manual mock\\. Define a factory function manually with `ManualMockedModule\\.fromJSON\\(\\)`\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mocker/src/registry.ts","lineNumber":87,"sourceCode":"        )\n      }\n      if (event.type === 'automock') {\n        const module = AutomockedModule.fromJSON(event)\n        this.add(module)\n        return module\n      }\n      else if (event.type === 'autospy') {\n        const module = AutospiedModule.fromJSON(event)\n        this.add(module)\n        return module\n      }\n      else if (event.type === 'redirect') {\n        const module = RedirectedModule.fromJSON(event)\n        this.add(module)\n        return module\n      }\n      else if (event.type === 'manual') {\n        throw new Error(`Cannot set serialized manual mock. Define a factory function manually with \\`ManualMockedModule.fromJSON()\\`.`)\n      }\n      else {\n        throw new Error(`Unknown mock type: ${(event as any).type}`)\n      }\n    }\n\n    if (typeof raw !== 'string') {\n      throw new TypeError('[vitest] Mocks require a raw string.')\n    }\n\n    if (typeof url !== 'string') {\n      throw new TypeError('[vitest] Mocks require a url string.')\n    }\n\n    if (typeof id !== 'string') {\n      throw new TypeError('[vitest] Mocks require an id string.')\n    }\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/mocker/src/registry.ts#L69-L105","documentation":"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).","triggerScenarios":"Calling `registry.register({ type: 'manual', raw, id, url })` — the serialized form of a manual mock — without providing a factory function.","commonSituations":"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.","solutions":["Reconstruct with an explicit factory: `const m = ManualMockedModule.fromJSON(data, () => ({ default: stub })); registry.add(m)`.","Or register via the positional overload: `registry.register('manual', data.raw, data.id, data.url, factory)`.","Do not attempt to round-trip manual mocks through JSON; transfer only their identity and rebuild the factory on the receiver."],"exampleFix":"// before (fails — no factory)\nregistry.register({ type: 'manual', raw, id, url })\n\n// after\nregistry.register('manual', data.raw, data.id, data.url, () => ({\n  default: vi.fn(),\n}))","handlingStrategy":"validation","validationCode":"function registerManual(registry: any, data: any, factory: () => unknown) {\n  if (data?.type === 'manual' && typeof factory !== 'function') {\n    throw new Error('Manual mocks require a factory; cannot restore from JSON alone.')\n  }\n  if (data?.type === 'manual') {\n    registry.add(\n      ManualMockedModule.fromJSON(data, factory),\n    )\n  } else {\n    registry.register(data)\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never attempt to serialize manual mocks for IPC without keeping the factory available on the receiver.","Transfer only automock/autospy/redirect mocks as JSON; rebuild manual mocks locally.","Document factory ownership in mock-sync code so receivers know to supply one."],"tags":["mocking","registry","serialization","manual-mock"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}