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

  1. Check the .baml enum definition and remove the add_value call for values already declared there.
  2. Guard the call: only add the value if it's absent (e.g. track added values or catch this error and ignore it).
  3. Move the value from runtime add_value calls into the .baml schema if it's static.
  4. 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

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


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