pydantic/monty · error · TypeError
wrapper id '${id}' already identifies a different object in
Error message
wrapper id '${id}' already identifies a different object in this session What it means
InstanceStore keys wrappers by session-local uuid; ids must be unambiguous or method calls and round-trips would silently route to the wrong host object. checkNoAlias (used by register, registerClass and registerClassIfAbsent) throws this TypeError when the id is already mapped to a different object — compared by strict identity of the wrapped instance/class.
Source
Thrown at crates/monty-js/ts/classInstance.ts:459
* is not yet registered — used for the `ClassType` a `ClassInstance`
* materializes, so an auto-built default policy never clobbers an
* explicitly granted one. Still rejects an id aliasing a different object. */
registerClassIfAbsent(wrapper: ClassType): string {
this.checkNoAlias(wrapper.id, wrapper.classType)
if (!this.map.has(wrapper.id)) {
this.map.set(wrapper.id, wrapper)
}
return wrapper.id
}
/** Throws if `id` is already registered for an object other than `value`
* (compared by identity). Two wrappers sharing an id but wrapping
* different objects would silently re-route method calls and round-trips
* from one host object to the other. */
private checkNoAlias(id: string, value: object): void {
const existing = this.map.get(id)
if (existing !== undefined && existing.instance !== value) {
throw new TypeError(`wrapper id '${id}' already identifies a different object in this session`)
}
}
/** Looks up the wrapper registered for `id` (instance or class type). */
get(id: string): BaseWrapper | undefined {
return this.map.get(id)
}
}
/**
* Internal sentinel thrown by [`ClassInstance.lookupLazyAttr`] /
* [`ClassInstance.callMethod`] when a name is outside the wrapper's policy or
* absent; the session layer turns it into a sandbox `AttributeError`. Not
* exported from the package index.
*/
export class AttrNotExposed extends Error {
constructor(message: string) {
super(message)View on GitHub (pinned to adc986b362)
Solutions
- Use a distinct uuid for each distinct object; generate ids with uuid4 or omit `id` so one is generated.
- Re-send the same wrapper (or another wrapper of the same object) — re-registering the same object under its id is allowed and overwrites.
- Check `store.get(id)` and only register when it is undefined or wraps the same object (`wrapper.instance === value`).
- If restoring dumps, make sure the id pinned via options.id matches the object it was originally issued for.
Example fix
// before
store.register(new ClassInstance(userA, { id: myId }))
store.register(new ClassInstance(userB, { id: myId })) // TypeError: alias
// after
store.register(new ClassInstance(userA, { id: idForA }))
store.register(new ClassInstance(userB, { id: generateUuid() })) Defensive patterns
Strategy: validation
Validate before calling
function safeRegister(store: InstanceStore, wrapper: ClassInstance): string {
const existing = store.get(wrapper.id)
if (existing !== undefined && existing.instance !== wrapper.instance) {
throw new TypeError(`id ${wrapper.id} already used for a different object`)
}
return store.register(wrapper)
} Type guard
function idIsFreeOrSame(store: InstanceStore, id: string, value: object): boolean {
const existing = store.get(id)
return existing === undefined || existing.instance === value
} Try / catch
try {
store.register(wrapper)
} catch (e) {
if (e instanceof TypeError && /already identifies a different object/.test(e.message)) {
// regenerate identity for the second object rather than aliasing
wrapper = new ClassInstance(wrapper.instance) // fresh uuid4 id
store.register(wrapper)
} else throw e
} Prevention
- Only pin ids (options.id) when restoring dumps; let wrappers auto-generate uuids otherwise
- Never reuse a pinned id constant for a second object in the same session
- Keep a host-side map object→id and always look it up before choosing an id
- If ids come from external input (snapshot files), validate they match the object identity before registering
When it happens
Trigger: Explicitly passing the same `id` option to wrappers of two different objects (`new ClassInstance(a, { id })` then `new ClassInstance(b, { id })`) or to a ClassType whose class differs from what the id already maps to, then sending the second wrapper in the same session (prepare/registerClass).
Common situations: Hard-coding or copying a pinned id from a snapshot-restoration setup into a second wrapper; restoring a dump in a fresh session where a different object was already registered under that id; generating ids from unstable input (e.g. name hashing) that collide.
Related errors
- ${what} must be a canonical uuid string
- ClassInstance expects an object instance
- notCallableMessage(method)
- ClassInstance expects an instance of a class, not a null-pro
- classType does not match the instance's class
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/61be2aae6d857827.
Report an issue: GitHub.