{"record":{"id":"a0420af910d22294","repo":"BoundaryML/baml","slug":"class-name-already-exists-type-builder","errorCode":null,"errorMessage":"Class ${name} already exists","messagePattern":"Class (.+?) already exists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"engine/language_client_typescript/typescript_src/type_builder.ts","lineNumber":110,"sourceCode":"\n  classBuilder<Name extends string, Properties extends string>(\n    name: Name,\n    properties: Properties[],\n  ): ClassBuilder<Name, Properties> {\n    return new ClassBuilder(this.tb, name, new Set(properties))\n  }\n\n  enumViewer<Name extends string, Values extends string>(name: Name, values: Values[]): EnumViewer<Name, Values> {\n    return new EnumViewer(this.tb, name, new Set(values))\n  }\n\n  enumBuilder<Name extends string, Values extends string>(name: Name, values: Values[]): EnumBuilder<Name, Values> {\n    return new EnumBuilder(this.tb, name, new Set(values))\n  }\n\n  addClass<Name extends string>(name: Name): ClassBuilder<Name> {\n    if (this.classes.has(name)) {\n      throw new Error(`Class ${name} already exists`)\n    }\n    if (this.enums.has(name)) {\n      throw new Error(`Enum ${name} already exists`)\n    }\n    this.classes.add(name)\n    return new ClassBuilder(this.tb, name)\n  }\n\n  addEnum<Name extends string>(name: Name): EnumBuilder<Name> {\n    if (this.classes.has(name)) {\n      throw new Error(`Class ${name} already exists`)\n    }\n    if (this.enums.has(name)) {\n      throw new Error(`Enum ${name} already exists`)\n    }\n    this.enums.add(name)\n    return new EnumBuilder(this.tb, name)\n  }","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_typescript/typescript_src/type_builder.ts#L92-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst cls = tb.addClass('Person')\n// later, same tb\nconst cls2 = tb.addClass('Person') // throws\n// after\nconst existing = seenClasses.has('Person') ? tb.class('Person') : tb.addClass('Person')\nseenClasses.add('Person')","handlingStrategy":"validation","validationCode":"// maintain your own registry before calling addClass\nif (registeredNames.has(name)) throw new Error(`duplicate registration: ${name}`)\nregisteredNames.add(name)","typeGuard":null,"tryCatchPattern":"try {\n  const cls = tb.addClass(name)\n} catch (e) {\n  if (e.message.includes('already exists')) return tb.class(name)\n  throw e\n}","preventionTips":["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."],"tags":["typescript","schema","duplicate","type-builder"],"backgroundTag":"file-already-exists","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}