pydantic/monty · error · TypeError

pass name on the ClassType wrapper, not alongside classType

Error message

pass name on the ClassType wrapper, not alongside classType

What it means

When both classType and name are passed to ClassInstance, this TypeError is thrown: the name is a class-level property, and once an explicit ClassType wrapper is provided the display name must be set on that wrapper, not duplicated at the instance level. This keeps the instance, its type object and error messages all reporting one consistent name.

Source

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

   *  `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 class
 *  object itself (class constants, static methods), the `init` gate, and the
 *  `instance*` policies applied to every constructed instance. */
export interface ClassTypeOptions extends BaseWrapperOptions {

View on GitHub (pinned to adc986b362)

Solutions

  1. Move the name onto the ClassType wrapper: `new ClassType(User, { name: 'User' })` and drop `name` from ClassInstanceOptions.
  2. Remove the `name` option from the ClassInstance call when classType is present.
  3. If no class-level policies are needed, drop classType instead and keep `name` — the default ClassType will be built with that name.

Example fix

// before
new ClassInstance(user, { classType: userType, name: 'User' }) // TypeError
// after
const userType = new ClassType(User, { name: 'User' })
new ClassInstance(user, { classType: userType })
Defensive patterns

Strategy: validation

Validate before calling

function classInstanceOptions(instance: object, opts: { classType?: ClassType; name?: string }) {
  if (opts.classType !== undefined && opts.name !== undefined) {
    throw new TypeError('pass name on the ClassType wrapper, not alongside classType')
  }
  return opts
}

Try / catch

try {
  wrapper = new ClassInstance(user, opts)
} catch (e) {
  if (e instanceof TypeError && /pass name on the ClassType wrapper/.test(e.message)) {
    const { name, ...rest } = opts
    wrapper = new ClassInstance(user, { ...rest, classType: new ClassType(user.constructor, { name }) })
  } else throw e
}

Prevention

When it happens

Trigger: `new ClassInstance(user, { classType: userType, name: 'User' })` — passing name alongside an explicit classType wrapper.

Common situations: Copy-pasting options between the two construction styles (with and without classType); switching from the default (auto-materialized) ClassType to an explicit one and leaving the old `name` option in place.

Related errors


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