quickwit-oss/tantivy · error

Field already exists in schema {}

Error message

Field already exists in schema {}

What it means

SchemaBuilder::add_field registers each field name uniquely in the schema's field map. Adding a field whose name already exists in the schema panics with 'Field already exists in schema <name>'. Field names are the primary lookup key, so duplicates are treated as a programming error rather than a recoverable error.

Source

Thrown at src/schema/schema.rs:221

    pub fn add_custom_field<T: Into<String>>(
        &mut self,
        field_name: &str,
        type_name: T,
        params: serde_json::Value,
    ) -> Field {
        let field_entry = FieldEntry::new_custom(
            field_name.to_string(),
            CustomOptions::new(type_name, params),
        );
        self.add_field(field_entry)
    }

    /// Adds a field entry to the schema in build.
    pub fn add_field(&mut self, field_entry: FieldEntry) -> Field {
        let field = Field::from_field_id(self.fields.len() as u32);
        let field_name = field_entry.name().to_string();
        if let Some(_previous_value) = self.fields_map.insert(field_name, field) {
            panic!("Field already exists in schema {}", field_entry.name());
        };
        self.fields.push(field_entry);
        field
    }

    /// Finalize the creation of a `Schema`
    /// This will consume your `SchemaBuilder`
    pub fn build(self) -> Schema {
        Schema(Arc::new(InnerSchema {
            fields: self.fields,
            fields_map: self.fields_map,
        }))
    }
}
#[derive(Debug)]
struct InnerSchema {
    fields: Vec<FieldEntry>,
    fields_map: HashMap<String, Field>, // transient

View on GitHub (pinned to b5d8deb80c)

Solutions

  1. De-duplicate field definitions before building: keep a HashSet of names and skip already-added ones.
  2. Check the builder's existing names first (e.g. via a helper on Schema/schema fields) before each add_*_field call.
  3. If merging schemas/configs, prefer explicit override semantics: replace the existing entry instead of adding a duplicate.

Example fix

// before
builder.add_u64_field("timestamp", Indexed);
builder.add_date_field("timestamp", Indexed); // panics
// after
let mut seen = HashSet::new();
if seen.insert("timestamp".to_string()) {
    builder.add_date_field("timestamp", Indexed);
}
Defensive patterns

Strategy: validation

Validate before calling

let mut names = HashSet::new();
if !names.insert(field_entry.name().to_string()) {
    return Err(format!("duplicate field: {}", field_entry.name()));
}
builder.add_field(field_entry);

Try / catch

// panic on duplicate name; guard before adding
assert!(!existing_names.contains(field_name), "duplicate schema field: {field_name}");

Prevention

When it happens

Trigger: Calling SchemaBuilder::add_field (or any of add_u64_field/add_i64_field/add_f64_field/add_bool_field/add_date_field/add_ip_addr_field) with a field_entry whose name was already added to the builder in the current build.

Common situations: Programmatically building a schema from config where a field is listed twice (e.g. defaults plus user overrides both defining 'timestamp'); merging field lists from multiple sources; loops that re-add the same field name; loading a saved JSON schema and re-adding defaults on top.

Related errors


AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05). Data as JSON: /api/errors/0f007f78d1590a4e. Report an issue: GitHub.