pydantic/monty · error · TypeError
classType does not match the instance's class
Error message
classType does not match the instance's class
What it means
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.
Source
Thrown at crates/monty-js/ts/classInstance.ts:221
* `TypeError`. */
readonly id: string
/** The [`ClassType`] wrapper carrying the class's identity and policies:
* `options.classType` if given, else a default one materialized from the
* constructor. */
readonly classType: ClassType
declare readonly options: ClassInstanceOptions
constructor(instance: object, options: ClassInstanceOptions = {}) {
super(instance, options)
this.id = options.id === undefined ? generateUuid() : normalizeId('ClassInstance', options.id)
const ctor = classOf(instance)
if (ctor === undefined) {
throw new TypeError('ClassInstance expects an instance of a class, not a null-prototype object')
}
if (options.classType !== undefined) {
if (options.classType.classType !== ctor) {
throw new TypeError("classType does not match the instance's class")
}
if (options.name !== undefined) {
throw new TypeError('pass name on the ClassType wrapper, not alongside classType')
}
this.classType = options.classType
} else {
this.classType = new ClassType(ctor as new (...args: never[]) => object, { name: options.name })
}
}
/** Class name shown to the sandbox: the class wrapper's, so the instance,
* its type object and error messages all agree. */
override getName(): string {
return this.classType.getName()
}
}
/** Options for [`ClassType`]: the inherited policies applied to the classView on GitHub (pinned to adc986b362)
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.
Example fix
// before
new ClassInstance(baseUser, { classType: userType /* ClassType(AdminUser) */ }) // TypeError
// after
new ClassInstance(baseUser, { classType: new ClassType(User, { name: 'User' }) }) Defensive patterns
Strategy: validation
Validate before calling
function isValidClassInstancePair(instance: object, classType: ClassType): boolean {
return classType.classType === (Object.getPrototypeOf(instance)?.constructor)
} Type guard
function wrapsSameClass(instance: object, classType: ClassType): boolean {
const ctor = Object.getPrototypeOf(instance)?.constructor
return typeof ctor === 'function' && ctor === classType.classType
} Try / catch
try {
const wrapper = new ClassInstance(instance, { classType })
} catch (e) {
if (e instanceof TypeError && /classType does not match/.test(e.message)) {
// fall back to the default ClassType materialized from the instance
const wrapper = new ClassInstance(instance)
} else throw e
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- pass name on the ClassType wrapper, not alongside classType
- ClassType expects a class (constructor function)
- Cannot convert ${constructorName(value)} instance to a Monty
- ${field} must be 'all', undefined or a list/Set of names, go
- invalid mount mode: '${mode}'. Expected 'read-only', 'read-w
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/21a4b1ca27d143fb.
Report an issue: GitHub.