{"record":{"id":"d24db87e6c8f32a0","repo":"BoundaryML/baml","slug":"property-name-already-exists-type-builder","errorCode":null,"errorMessage":"Property ${name} already exists.","messagePattern":"Property (.+?) already exists\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"engine/language_client_typescript/typescript_src/type_builder.ts","lineNumber":185,"sourceCode":"  property(name: string): ClassPropertyViewer {\n    if (!this.properties.has(name)) {\n      throw new Error(`Property ${name} not found.`)\n    }\n    return new ClassPropertyViewer()\n  }\n}\n\nexport class ClassBuilder<ClassName extends string, Properties extends string = string> extends ClassAst<\n  ClassName,\n  Properties\n> {\n  constructor(tb: _TypeBuilder, name: ClassName, properties: Set<Properties | string> = new Set()) {\n    super(tb, name, properties)\n  }\n\n  addProperty<S extends string>(name: RestrictNot<ClassName, S, Properties>, type: FieldType): ClassPropertyBuilder {\n    if (this.properties.has(name)) {\n      throw new Error(`Property ${name} already exists.`)\n    }\n    this.properties.add(name)\n    return new ClassPropertyBuilder(this.bldr.property(name).setType(type))\n  }\n\n  listProperties(): Array<[string, ClassPropertyBuilder]> {\n    return (this.bldr.listProperties() as Array<[string, _ClassPropertyBuilder]>).map(\n      ([name, prop]) => [name, new ClassPropertyBuilder(prop)],\n    )\n  }\n\n  removeProperty(name: string): void {\n    this.properties.delete(name)\n    this.bldr.removeProperty(name)\n  }\n\n  reset(): void {\n    this.bldr.reset()","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_typescript/typescript_src/type_builder.ts#L167-L203","documentation":"ClassBuilder.addProperty throws when a property with the same name has already been added to the class. The builder tracks property names in a Set and rejects duplicates so the generated BAML class has unique fields.","triggerScenarios":"Calling classBuilder.addProperty('title', ...) twice on the same ClassBuilder, or a loop mapping object keys to properties that runs twice (e.g. retry or merge path).","commonSituations":"Merging two JSON schemas that share field names; building a class once at module load and again in a hot-reload callback.","solutions":["Skip addProperty when the name is already present (check your own registry or listProperties).","Use the returned property builder to update the type instead of re-adding.","Recreate the ClassBuilder if stale state accumulates across rebuilds."],"exampleFix":"// before\nclassBuilder.addProperty('id', t.string())\nclassBuilder.addProperty('id', t.int()) // throws\n// after\nif (!addedProps.has('id')) { classBuilder.addProperty('id', t.string()); addedProps.add('id') }","handlingStrategy":"validation","validationCode":"if (classBuilder.listProperties().some(([n]) => n === name)) return // already added\nclassBuilder.addProperty(name, type)","typeGuard":null,"tryCatchPattern":"try {\n  classBuilder.addProperty(name, type)\n} catch (e) {\n  if (e.message.includes('already exists')) return\n  throw e\n}","preventionTips":["Deduplicate input field definitions (e.g. by object key) before mapping to addProperty.","Build classes once at module init, not per-request without reset.","Track added properties in a Set alongside the builder."],"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"}