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

  1. Guard registration: only call addClass if the name has not been added (track it yourself or check before adding).
  2. Create a new TypeBuilder (or call its reset) per request instead of reusing a partially built one.
  3. 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

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


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/a0420af910d22294. Report an issue: GitHub.