BoundaryML/baml · error

Enum with name {name} already exists

Error message

Enum with name {name} already exists

What it means

TypeBuilder::add_enum refuses to create an enum whose name is already defined in the runtime IR. BAML treats enum names as unique; adding a duplicate would create an ambiguous schema, so the call bails instead.

Source

Thrown at engine/language_client_cffi/src/raw_ptr_wrapper/type_builder/objects.rs:61

        assert!(NodeRW::LLMOnly.at_least(NodeRW::LLMOnly).is_ok());
        assert!(NodeRW::LLMOnly.at_least(NodeRW::ReadWrite).is_err());

        assert!(NodeRW::ReadWrite.at_least(NodeRW::ReadOnly).is_ok());
        assert!(NodeRW::ReadWrite.at_least(NodeRW::LLMOnly).is_ok());
        assert!(NodeRW::ReadWrite.at_least(NodeRW::ReadWrite).is_ok());
    }
}

#[derive(Debug, Clone, Default)]
pub struct TypeBuilder {
    pub type_builder: RuntimeTypeBuilder,
}

impl TypeBuilder {
    pub fn add_enum(&self, rt: &BamlRuntime, name: &str) -> anyhow::Result<EnumBuilder> {
        match rt.ir.find_enum(name) {
            Ok(_) => {
                anyhow::bail!("Enum with name {name} already exists");
            }
            Err(_) => {
                let _ = self.type_builder.upsert_enum(name);
                let builder = EnumBuilder::new(self.type_builder.clone(), name.to_string());
                Ok(builder.mode(NodeRW::ReadWrite))
            }
        }
    }

    pub fn add_class(&self, rt: &BamlRuntime, name: &str) -> anyhow::Result<ClassBuilder> {
        match rt.ir.find_class(name) {
            Ok(_) => {
                anyhow::bail!("Class with name {name} already exists");
            }
            Err(_) => {
                let _ = self.type_builder.upsert_class(name);
                let builder = ClassBuilder::new(self.type_builder.clone(), name.to_string());
                Ok(builder.mode(NodeRW::ReadWrite))

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Use tb.r#enum(rt, name) to fetch and modify the existing enum instead of add_enum
  2. Check existence first (match rt.ir / wrap in a check) and only call add_enum for new names
  3. Rename the new enum to avoid the collision

Example fix

// before
let eb = tb.add_enum(rt, "Color")?; // fails if Color exists
// after
let eb = match tb.r#enum(rt, "Color") {
    Ok(eb) => eb,
    Err(_) => tb.add_enum(rt, "Color")?,
};
Defensive patterns

Strategy: try-catch

Validate before calling

# caller side: check before add
if enum_exists(rt, "Color"):
    eb = tb.enum("Color")
else:
    eb = tb.add_enum(rt, "Color")

Try / catch

try:
    eb = tb.add_enum(rt, name)
except Exception as e:
    if "already exists" in str(e):
        eb = tb.enum(name)
    else:
        raise

Prevention

When it happens

Trigger: Calling tb.add_enum(rt, "Name") when an enum named 'Name' already exists in the BAML source the runtime was compiled from, or when add_enum was already called for that name.

Common situations: Dynamically adding an enum that duplicates one declared in .baml files; re-running builder setup code without idempotency checks; name collisions between dynamic enums and statically-declared ones.

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/fa4c928c74876d0a. Report an issue: GitHub.