BoundaryML/baml · error · Error
Value already exists.
Error message
Value ${name} already exists. What it means
EnumValueBuilder.addValue throws this when the enum already contains a value with the given name. The builder guards against duplicate enum members because BAML enums require unique value names; adding the same name twice would produce an invalid enum definition. It is a deliberate programmer-error guard, not a runtime condition.
Solutions
- Deduplicate the source list before calling addValue, e.g. [...new Set(names)]
- Guard each call with a membership check or wrap it in try/catch and skip existing values
- Rebuild the TypeBuilder/enum from scratch instead of re-adding values to an existing builder
- If the duplicate is intentional (same semantic value from two sources), normalize the source data upstream
Example fix
// before
for (const v of configValues) {
enumBuilder.addValue(v.name);
}
// after
for (const v of [...new Set(configValues)]) {
if (!enumBuilder.listValues().some(([n]) => n === v.name)) {
enumBuilder.addValue(v.name);
}
} Defensive patterns
Strategy: validation
Validate before calling
if (enumBuilder.listValues().some(([existing]) => existing === newName)) {
throw new Error(`Cannot add duplicate enum value: ${newName}`);
}
enumBuilder.addValue(newName); Prevention
- Deduplicate name lists ([...new Set(names)]) before feeding addValue
- Build enums from scratch on each rebuild instead of mutating a shared builder
- Centralize enum construction in one function so adds are traceable
When it happens
Trigger: Calling addValue(name) on an EnumValueBuilder whose underlying values Set already contains name. This happens when the same value name is added twice in a builder chain, or when a loop/config list feeding addValue contains duplicates, or when addValue is called for a name that was passed into the TypeBuilder enum constructor's initial values Set.
Common situations: Building BAML enums dynamically from config files or database rows that contain duplicate entries; merging enum values from two sources without deduplicating; copy-pasted builder code that adds the same literal twice; hot-reload code that re-adds values onto an existing builder without resetting it.
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/d90b07e16aff70b3.
Report an issue: GitHub.
Appendix: source
Thrown at engine/language_client_typescript/typescript_src/type_builder.ts:289
if (!this.values.has(name)) {
throw new Error(`Value ${name} not found.`)
}
return new EnumValueViewer()
}
}
export class EnumValueViewer {
constructor() {}
}
export class EnumBuilder<EnumName extends string, T extends string = string> extends EnumAst<EnumName, T> {
constructor(tb: _TypeBuilder, name: EnumName, values: Set<T | string> = new Set()) {
super(tb, name, values)
}
addValue<S extends string>(name: RestrictNot<EnumName, S, T>): EnumValueBuilder {
if (this.values.has(name)) {
throw new Error(`Value ${name} already exists.`)
}
this.values.add(name)
return this.bldr.value(name)
}
listValues(): Array<[string, EnumValueBuilder]> {
return Array.from(this.values).map((name) => [name, this.bldr.value(name)])
}
value(name: string): EnumValueBuilder {
return this.bldr.value(name)
}
}
View on GitHub (pinned to bd85ce9dee)