pydantic/monty · error · TypeError

ClassType expects a class (constructor function)

Error message

ClassType expects a class (constructor function)

What it means

ClassType wraps a host class so it can cross into the Monty sandbox (and optionally be instantiated there with init: true). Its constructor validates up front that the value is actually a class — a constructor function — and throws this TypeError for anything else (plain objects, class instances, primitives, arrow functions without constructor semantics used as classes).

Source

Thrown at crates/monty-js/ts/classInstance.ts:285

 *
 * ```ts
 * await session.feedRun('p = Point(1, 2)\nassert p.x == 1', {
 *   inputs: { Point: new ClassType(Point, { init: true, instanceEagerAttrs: 'all' }) },
 * })
 * ```
 */
export class ClassType extends BaseWrapper {
  /** The class's sandbox identity. Defaults to a process-wide id per class
   *  object (every wrapper of one class agrees), so instances keep a stable
   *  type identity; pass `id` to pin it explicitly, e.g. when restoring a
   *  dump in a fresh process. */
  readonly id: string

  declare readonly options: ClassTypeOptions

  constructor(classType: new (...args: never[]) => object, options: ClassTypeOptions = {}) {
    if (typeof classType !== 'function') {
      throw new TypeError('ClassType expects a class (constructor function)')
    }
    super(classType, options)
    validatePolicy('instanceEagerAttrs', options.instanceEagerAttrs)
    validatePolicy('instanceLazyAttrs', options.instanceLazyAttrs)
    validatePolicy('instanceAllowedMethods', options.instanceAllowedMethods)
    this.id = options.id === undefined ? classIdFor(classType) : normalizeId('ClassType', options.id)
  }

  /** The wrapped host class (the inherited `instance` field). */
  get classType(): new (...args: never[]) => object {
    return this.instance as new (...args: never[]) => object
  }

  /** Class name shown to the sandbox: `options.name`, else the class name. */
  override getName(): string {
    if (this.options.name !== undefined) {
      return this.options.name
    }

View on GitHub (pinned to adc986b362)

Solutions

  1. Pass the class itself, not an instance: `new ClassType(Point, ...)` instead of `new ClassType(new Point(), ...)`.
  2. Check `typeof value === 'function'` and that it has a prototype before wrapping.
  3. If the value is a plain factory function, convert it to a class or wrap instances of its results individually with ClassInstance.
  4. Verify imports resolve to the class (check for wrong default/named import or undefined under ESM circular imports).

Example fix

// before
const point = new Point(1, 2)
new ClassType(point, { init: true }) // TypeError
// after
new ClassType(Point, { init: true, instanceEagerAttrs: 'all' })
Defensive patterns

Strategy: validation

Validate before calling

function isClass(value: unknown): value is new (...args: never[]) => object {
  return typeof value === 'function' && /^class\s/.test(Function.prototype.toString.call(value))
}
if (!isClass(maybeClass)) throw new TypeError('ClassType requires a class constructor')

Type guard

function isConstructorFunction(value: unknown): value is new (...args: never[]) => object {
  if (typeof value !== 'function') return false
  const desc = Object.getOwnPropertyDescriptor(value, 'prototype')
  return desc !== undefined && !desc.writable // class constructors have non-writable prototype
}

Try / catch

try {
  const type = new ClassType(value, { init: true })
} catch (e) {
  if (e instanceof TypeError && /expects a class/.test(e.message)) {
    throw new TypeError(`${debugName(value)} is not a class — pass the constructor, not an instance`)
  } else throw e
}

Prevention

When it happens

Trigger: `new ClassType(point)` passing an instance instead of the class; `new ClassType(configObject)` passing a plain object; `new ClassType(null/undefined)`; passing something read out of a loosely typed registry or JSON config where the class was expected.

Common situations: Confusing the class with its instance (Point vs new Point()); importing a default export that is an object, not a class; typos resolving to undefined under a permissive tsconfig; trying to wrap a plain factory function that is not a constructor.

Related errors


AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13). Data as JSON: /api/errors/92d7039b6b2e2f7f. Report an issue: GitHub.