pydantic/monty · error · TypeError
ClassInstance expects an object instance
Error message
ClassInstance expects an object instance
What it means
A `TypeError` from the `BaseWrapper` constructor: `ClassInstance` (and `ClassType` via the shared base) only wraps host objects or functions, and the value passed as `instance` was neither — typically a primitive (`string`, `number`, `boolean`), `null`, or `undefined`. The wrapper must be able to store and route calls to a real object, so non-object values are rejected at construction time rather than failing later mid-session.
Source
Thrown at crates/monty-js/ts/classInstance.ts:78
/** A [`ClassType`] wrapper for the instance's class, overriding the default
* one materialized from the constructor — pass one to grant class-level
* policies (or a pinned class id) alongside the instance. Must wrap the
* instance's own constructor. Its eager class attrs are sent with every
* crossing of the instance, so `type(x)` in the sandbox sees them. */
classType?: ClassType
}
/** Shared behavior of [`ClassInstance`] and [`ClassType`]: the wrapped value,
* the attr/method exposure policies, and the dispatch entry points the
* session layer calls (`getEagerAttrs`, `lookupLazyAttr`, `callMethod`). */
export abstract class BaseWrapper {
constructor(
/** The wrapped host object; returned unchanged when the sandbox returns the instance. */
readonly instance: object,
readonly options: BaseWrapperOptions = {},
) {
if ((typeof instance !== 'object' && typeof instance !== 'function') || instance === null) {
throw new TypeError('ClassInstance expects an object instance')
}
validatePolicy('eagerAttrs', options.eagerAttrs)
validatePolicy('lazyAttrs', options.lazyAttrs)
validatePolicy('allowedMethods', options.allowedMethods)
}
/** Class name shown to the sandbox: `options.name`, else the constructor name. */
getName(): string {
if (this.options.name !== undefined) {
return this.options.name
}
return constructorName(this.instance)
}
/** The `[name, value]` attr pairs sent into the sandbox with the instance,
* each value already passed through `convertValue`. */
getEagerAttrs(): Array<[string, unknown]> {
const policy = this.options.eagerAttrsView on GitHub (pinned to adc986b362)
Solutions
- Pass the actual host object, not a primitive or its id
- Guard optional values before wrapping: if the value can be null/undefined, skip wrapping or throw your own clearer error
- If you only need a plain value in the sandbox, pass it directly as an input — do not wrap primitives in `ClassInstance`
Example fix
// before
const wrapper = user === undefined ? new ClassInstance(undefined) : new ClassInstance(user)
// after
if (user == null || typeof user !== 'object') throw new Error('expected a user object')
const wrapper = new ClassInstance(user, { eagerAttrs: 'all' }) Defensive patterns
Strategy: type-guard
Validate before calling
function assertWrappable(v: unknown): asserts v is object {
if (v === null || (typeof v !== 'object' && typeof v !== 'function')) {
throw new TypeError(`ClassInstance needs an object, got ${v === null ? 'null' : typeof v}`)
}
}
assertWrappable(candidate)
const wrapper = new ClassInstance(candidate) Type guard
const isWrappable = (v: unknown): v is object => v !== null && (typeof v === 'object' || typeof v === 'function')
Try / catch
try {
return new ClassInstance(candidate as object, opts)
} catch (err) {
if (err instanceof TypeError && err.message.includes('expects an object instance')) {
// pass the raw value through instead of wrapping
return candidate
}
throw err
} Prevention
- Type the wrapper input as `object` in your own code so primitives are rejected at compile time
- Null-check optional values before wrapping
- Do not wrap primitives 'to be safe' — pass them directly as session inputs
When it happens
Trigger: `new ClassInstance(42)`, `new ClassInstance(null)`, `new ClassInstance(undefined)`, or passing a primitive returned by another API (e.g. `JSON.parse` output that is a number/string) where a class instance was expected. Note `typeof x === 'function'` is accepted, so plain functions and classes pass this check.
Common situations: Refactoring that changed a variable from an object to an id; optional values left `undefined`; deserialized data whose shape drifted; calling `new ClassInstance(obj.id)` instead of `new ClassInstance(obj)`.
Related errors
- ClassInstance expects an instance of a class, not a null-pro
- ClassType expects a class (constructor function)
- MontyFileHandle path must be a string
- MontyFileHandle mode must be a string
- MontyFileHandle position must be a non-negative safe integer
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/e92a464bb653a688.
Report an issue: GitHub.