{"record":{"id":"21a4b1ca27d143fb","repo":"pydantic/monty","slug":"classtype-does-not-match-the-instance-s-class","errorCode":null,"errorMessage":"classType does not match the instance's class","messagePattern":"classType does not match the instance's class","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/monty-js/ts/classInstance.ts","lineNumber":221,"sourceCode":"   *  `TypeError`. */\n  readonly id: string\n  /** The [`ClassType`] wrapper carrying the class's identity and policies:\n   *  `options.classType` if given, else a default one materialized from the\n   *  constructor. */\n  readonly classType: ClassType\n\n  declare readonly options: ClassInstanceOptions\n\n  constructor(instance: object, options: ClassInstanceOptions = {}) {\n    super(instance, options)\n    this.id = options.id === undefined ? generateUuid() : normalizeId('ClassInstance', options.id)\n    const ctor = classOf(instance)\n    if (ctor === undefined) {\n      throw new TypeError('ClassInstance expects an instance of a class, not a null-prototype object')\n    }\n    if (options.classType !== undefined) {\n      if (options.classType.classType !== ctor) {\n        throw new TypeError(\"classType does not match the instance's class\")\n      }\n      if (options.name !== undefined) {\n        throw new TypeError('pass name on the ClassType wrapper, not alongside classType')\n      }\n      this.classType = options.classType\n    } else {\n      this.classType = new ClassType(ctor as new (...args: never[]) => object, { name: options.name })\n    }\n  }\n\n  /** Class name shown to the sandbox: the class wrapper's, so the instance,\n   *  its type object and error messages all agree. */\n  override getName(): string {\n    return this.classType.getName()\n  }\n}\n\n/** Options for [`ClassType`]: the inherited policies applied to the class","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/pydantic/monty/blob/adc986b362e3961f407868cb118a99fe831b9e61/crates/monty-js/ts/classInstance.ts#L203-L239","documentation":"ClassInstance accepts an optional classType option — a ClassType wrapper that must wrap exactly the same constructor as the instance being wrapped. This TypeError is thrown when the ClassType wrapper's underlying class (`options.classType.classType`) is not identical (===) to the constructor found on the instance's prototype chain, preventing an instance from crossing the wire with a mismatched type identity.","triggerScenarios":"Calling `new ClassInstance(instance, { classType: new ClassType(SomeOtherClass) })` where SomeOtherClass !== instance's actual constructor — e.g. reusing a ClassType wrapper built for a subclass while wrapping a base-class instance, copying a ClassType from a different domain/realm (the class functions differ by identity), or refactoring code so the classType variable now points at a different class.","commonSituations":"Centralizing a shared ClassType registry but wrapping the wrong instance; passing a parent ClassType for a subclass instance or vice versa; creating separate class copies (e.g. class re-declaration, module duplication via bundling) so === fails even though the names match.","solutions":["Make the ClassType wrap the exact same class as the instance: `new ClassInstance(user, { classType: new ClassType(User) })` where `user instanceof User`.","Omit the classType option entirely — ClassInstance materializes a default ClassType from the instance's constructor, inheriting options.name.","Check `new ClassType(X).classType === instance.constructor` before constructing the wrapper.","If the class crosses realms/bundles, use one canonical copy of the class so identity comparison succeeds."],"exampleFix":"// before\nnew ClassInstance(baseUser, { classType: userType /* ClassType(AdminUser) */ }) // TypeError\n// after\nnew ClassInstance(baseUser, { classType: new ClassType(User, { name: 'User' }) })","handlingStrategy":"validation","validationCode":"function isValidClassInstancePair(instance: object, classType: ClassType): boolean {\n  return classType.classType === (Object.getPrototypeOf(instance)?.constructor)\n}","typeGuard":"function wrapsSameClass(instance: object, classType: ClassType): boolean {\n  const ctor = Object.getPrototypeOf(instance)?.constructor\n  return typeof ctor === 'function' && ctor === classType.classType\n}","tryCatchPattern":"try {\n  const wrapper = new ClassInstance(instance, { classType })\n} catch (e) {\n  if (e instanceof TypeError && /classType does not match/.test(e.message)) {\n    // fall back to the default ClassType materialized from the instance\n    const wrapper = new ClassInstance(instance)\n  } else throw e\n}","preventionTips":["Always build the ClassType from the same class expression the instance is constructed from","Export one canonical ClassType per class from a shared module instead of recreating it","Assert instanceof against the exact class (not a base class) before combining wrappers","Avoid duplicating class definitions across bundles/realms — identity comparison requires one copy"],"tags":["typescript","type-mismatch","wrapper","configuration"],"backgroundTag":"invalid-argument-value","analyzedSha":"adc986b362e3961f407868cb118a99fe831b9e61","analyzedAt":"2026-09-13T19:19:18.698Z","contentChangedAt":"2026-09-13T19:19:18.698Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}