pydantic/monty · error · TypeError
ClassInstance expects an instance of a class, not a null-pro
Error message
ClassInstance expects an instance of a class, not a null-prototype object
What it means
A `TypeError` from the `ClassInstance` constructor: the value is a valid object, but its prototype chain has no constructor — i.e. it is a null-prototype object (e.g. built with `Object.create(null)`) — so `ClassInstance` cannot derive the sandbox-visible class (`classOf(instance)` returns undefined). The sandbox models every wrapped value as an instance of a named class, so a classless object cannot be represented as a `ClassInstance`.
Source
Thrown at crates/monty-js/ts/classInstance.ts:217
*/
export class ClassInstance extends BaseWrapper {
/** The instance's sandbox identity: reuse one wrapper to re-send an object
* under the same id; reusing an id for a different object throws
* `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()View on GitHub (pinned to adc986b362)
Solutions
- If it is just data, pass the plain record directly as a session input — plain objects cross without a wrapper
- Give the object a real prototype/class: build it from a class or add `Object.setPrototypeOf(obj, SomeClass.prototype)`
- Wrap a class-instance-shaped value instead, or expose static data via `ClassType` `eagerAttrs`
Example fix
// before
const record = Object.create(null)
new ClassInstance(record) // TypeError: null-prototype object
// after
class Record {}
const record = Object.assign(new Record(), data)
new ClassInstance(record, { eagerAttrs: 'all' }) Defensive patterns
Strategy: type-guard
Validate before calling
const hasRealClass = (v: object): boolean => {
const proto = Object.getPrototypeOf(v)
return proto !== null && typeof (proto as { constructor?: unknown }).constructor === 'function'
}
if (!hasRealClass(candidate)) {
// pass as a plain input instead of wrapping
inputs.data = candidate
} else {
inputs.obj = new ClassInstance(candidate)
} Type guard
const isClassInstance = (v: object): boolean =>
typeof (Object.getPrototypeOf(v) as { constructor?: unknown } | null)?.constructor === 'function' Try / catch
try {
wrapped = new ClassInstance(obj)
} catch (err) {
if (err instanceof TypeError && err.message.includes('null-prototype object')) {
// null-prototype records cross as plain values anyway
wrapped = obj
} else {
throw err
}
} Prevention
- Avoid `Object.create(null)` for objects destined for the sandbox; use `{}` or a class
- Do not re-wrap `MontyClassProxy.attributes` or other null-prototype records produced by the library
- Check `Object.getPrototypeOf(x)?.constructor` before choosing ClassInstance vs plain input
- Remember JSON.parse results DO have Object.prototype — this error is specific to prototype-stripped objects
When it happens
Trigger: Wrapping objects created via `Object.create(null)`, JSON-parse reviver outputs with stripped prototypes, or dictionary-style records built by this library's own walks (which deliberately use null-prototype objects); wrapping a `MontyClassProxy.attributes` record directly.
Common situations: Passing a key/value record that came from `Object.create(null)` (common in security-conscious code or sandboxes) as a `ClassInstance`; attempting to round-trip restored sandbox attribute records back into a new session as wrapped instances.
Related errors
- ClassInstance expects an object instance
- ClassType expects a class (constructor function)
- MontyFileHandle path must be a string
- MontyFileHandle mode must be a string
- notCallableMessage(method)
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/290985d6a2f4560f.
Report an issue: GitHub.