BoundaryML/baml · error
Enum value already exists: {} in enum {}
Error message
Enum value already exists: {} in enum {} What it means
Thrown by EnumBuilder::add_value() when the value you are trying to add is already declared on the enum in the compiled IR. The builder deliberately refuses duplicate additions: values coming from the AST are considered immutable, so re-adding them is treated as an invalid operation rather than a silent upsert.
Source
Thrown at engine/language_client_cffi/src/raw_ptr_wrapper/type_builder/objects.rs:600
}
};
EnumValueBuilder::new(
self.type_builder.clone(),
self.enum_name.clone(),
name.to_string(),
)
.mode(target_mode)
}
pub fn add_value(&self, rt: &BamlRuntime, value: &str) -> anyhow::Result<EnumValueBuilder> {
self.mode.at_least(NodeRW::ReadWrite)?;
let enm = self.enm(rt)?;
// if the IR already has the value, then its not valid to add it again
if let Ok(enm_ir) = rt.ir.find_enum(self.enum_name.as_str()) {
if enm_ir.find_value(value).is_some() {
anyhow::bail!(
"Enum value already exists: {} in enum {}",
value,
self.enum_name
);
}
}
let builder = enm.lock().unwrap();
let _ = builder.upsert_value(value);
Ok(self.create_value(value, rt))
}
pub fn set_description(&self, rt: &BamlRuntime, description: &str) -> anyhow::Result<()> {
self.mode.at_least(NodeRW::LLMOnly)?;
let enm = self.enm(rt)?;
let builder = enm.lock().unwrap();
builder.with_meta("description", BamlValue::String(description.to_string()));View on GitHub (pinned to bd85ce9dee)
Solutions
- Check the .baml enum definition and remove the add_value call for values already declared there.
- Guard the call: only add the value if it's absent (e.g. track added values or catch this error and ignore it).
- Move the value from runtime add_value calls into the .baml schema if it's static.
- Ensure patch code runs once, not on every request/session setup.
Example fix
// before
tb.enum("Color").add_value(rt, "red")?; // 'red' already in .baml
// after
if !declared_values.contains("red") {
tb.enum("Color").add_value(rt, "red")?;
} Defensive patterns
Strategy: validation
Validate before calling
let already = rt.ir.find_enum("Color")
.ok()
.map(|e| e.find_value("red").is_some())
.unwrap_or(false);
if !already {
tb.enum_("Color").add_value(rt, "red")?;
} Type guard
fn ir_has_enum_value(rt: &BamlRuntime, enum_name: &str, value: &str) -> bool {
rt.ir.find_enum(enum_name).map(|e| e.find_value(value).is_some()).unwrap_or(false)
} Try / catch
match enum_builder.add_value(rt, "red") {
Err(e) if e.to_string().contains("already exists") => { /* idempotent skip */ }
other => other?,
} Prevention
- Guard every add_value with an IR existence check for idempotent patching.
- Move static values into the .baml schema instead of adding them at runtime.
- Make type-builder patches idempotent — they may run more than once.
When it happens
Trigger: Calling tb.enum_("Color").add_value(rt, "red") when 'red' is already a value of enum Color in the .baml file. Also happens when runtime patching code runs on every request and re-adds a value that the schema already defines.
Common situations: idempotency bugs where type-builder patches execute multiple times; copying example code that adds a value the sample schema already has; migration scripts that add values now present in the schema.
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
- Type not found for property {} in class {}
- Enum not found: {}
- Enum value not found: {} in enum {}
- {0}
- interned member `{name}` cannot be another member's child
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/adc1784f8ed7b80d.
Report an issue: GitHub.