BoundaryML/baml · error · Error
Class ${name} already exists
Error message
Class ${name} already exists What it means
TypeBuilder.addClass throws when a class with the given name has already been registered in the type builder. The builder keeps a Set of class names and refuses duplicate registration to keep the generated BAML schema unambiguous. This is a developer bug in code that programmatically builds a dynamic client's types.
Source
Thrown at engine/language_client_typescript/typescript_src/type_builder.ts:110
classBuilder<Name extends string, Properties extends string>(
name: Name,
properties: Properties[],
): ClassBuilder<Name, Properties> {
return new ClassBuilder(this.tb, name, new Set(properties))
}
enumViewer<Name extends string, Values extends string>(name: Name, values: Values[]): EnumViewer<Name, Values> {
return new EnumViewer(this.tb, name, new Set(values))
}
enumBuilder<Name extends string, Values extends string>(name: Name, values: Values[]): EnumBuilder<Name, Values> {
return new EnumBuilder(this.tb, name, new Set(values))
}
addClass<Name extends string>(name: Name): ClassBuilder<Name> {
if (this.classes.has(name)) {
throw new Error(`Class ${name} already exists`)
}
if (this.enums.has(name)) {
throw new Error(`Enum ${name} already exists`)
}
this.classes.add(name)
return new ClassBuilder(this.tb, name)
}
addEnum<Name extends string>(name: Name): EnumBuilder<Name> {
if (this.classes.has(name)) {
throw new Error(`Class ${name} already exists`)
}
if (this.enums.has(name)) {
throw new Error(`Enum ${name} already exists`)
}
this.enums.add(name)
return new EnumBuilder(this.tb, name)
}View on GitHub (pinned to bd85ce9dee)
Solutions
- Guard registration: only call addClass if the name has not been added (track it yourself or check before adding).
- Create a new TypeBuilder (or call its reset) per request instead of reusing a partially built one.
- Rename one of the conflicting classes if they are genuinely distinct types.
Example fix
// before
const cls = tb.addClass('Person')
// later, same tb
const cls2 = tb.addClass('Person') // throws
// after
const existing = seenClasses.has('Person') ? tb.class('Person') : tb.addClass('Person')
seenClasses.add('Person') Defensive patterns
Strategy: validation
Validate before calling
// maintain your own registry before calling addClass
if (registeredNames.has(name)) throw new Error(`duplicate registration: ${name}`)
registeredNames.add(name) Try / catch
try {
const cls = tb.addClass(name)
} catch (e) {
if (e.message.includes('already exists')) return tb.class(name)
throw e
} Prevention
- Build a fresh TypeBuilder per request instead of reusing one.
- Centralize type registration in a single idempotent function.
- Never register types inside retry/hot-reload callbacks without reset.
When it happens
Trigger: Calling typeBuilder.addClass('Foo') twice on the same builder instance, or in a loop/helper that re-registers classes on each iteration without a fresh TypeBuilder.
Common situations: Hot-reload or retry paths that rebuild a TypeBuilder without resetting it; registering the same base class in multiple helper functions against a shared builder.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Property ${name} already exists.
- Enum with name {name} already exists
- Class with name {name} already exists
- Enum ${name} already exists
- Property ${name} not found.
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/a0420af910d22294.
Report an issue: GitHub.