quickwit-oss/quickwit · error

concatenate type must have at least one sub-field

Error message

concatenate type must have at least one sub-field

What it means

A `concatenate` field builds a combined searchable text from sub-fields. It must list at least one `concatenate_fields`, unless `include_dynamic_fields` is true (in which case dynamic fields provide the input). An empty list with dynamic fields disabled leaves the concatenate field with no source data, so deserialization bails.

Source

Thrown at quickwit/quickwit-doc-mapper/src/doc_mapper/field_mapping_entry.rs:740

    quickwit_field_type: QuickwitFieldType,
    json: JsonValue,
) -> anyhow::Result<FieldMappingType> {
    let (typ, cardinality) = match quickwit_field_type {
        QuickwitFieldType::Simple(typ) => (typ, Cardinality::SingleValued),
        QuickwitFieldType::Array(typ) => (typ, Cardinality::MultiValued),
        QuickwitFieldType::Object => {
            let object_options: QuickwitObjectOptions = serde_json::from_value(json)?;
            if object_options.field_mappings.is_empty() {
                anyhow::bail!("object type must have at least one field mapping");
            }
            return Ok(FieldMappingType::Object(object_options));
        }
        QuickwitFieldType::Concatenate => {
            let concatenate_options: QuickwitConcatenateOptions = serde_json::from_value(json)?;
            if concatenate_options.concatenate_fields.is_empty()
                && !concatenate_options.include_dynamic_fields
            {
                anyhow::bail!("concatenate type must have at least one sub-field");
            }
            return Ok(FieldMappingType::Concatenate(concatenate_options));
        }
    };
    match typ {
        Type::Str => {
            let text_options: QuickwitTextOptions = serde_json::from_value(json)?;
            Ok(FieldMappingType::Text(text_options, cardinality))
        }
        Type::U64 => {
            let numeric_options: QuickwitNumericOptions = serde_json::from_value(json)?;
            Ok(FieldMappingType::U64(numeric_options, cardinality))
        }
        Type::I64 => {
            let numeric_options: QuickwitNumericOptions = serde_json::from_value(json)?;
            Ok(FieldMappingType::I64(numeric_options, cardinality))
        }
        Type::F64 => {

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Populate `concatenate_fields` with at least one text field name.
  2. Set `include_dynamic_fields: true` if you intend the concatenate field to cover dynamic fields.
  3. If neither applies, remove the concatenate field from the mapping.

Example fix

// before
{name: "all", type: "concatenate", concatenate_fields: [], include_dynamic_fields: false}
// after
{name: "all", type: "concatenate", concatenate_fields: ["title", "body"], include_dynamic_fields: false}
Defensive patterns

Strategy: validation

Validate before calling

fn concatenate_has_sources(f: &serde_json::Value) -> bool {
    if f.get("type").and_then(|t| t.as_str()) == Some("concatenate") {
        let has_fields = f.get("concatenate_fields")
            .and_then(|m| m.as_array())
            .map_or(false, |a| !a.is_empty());
        let dynamic = f.get("include_dynamic_fields")
            .and_then(|v| v.as_bool()) == Some(true);
        has_fields || dynamic
    } else { true }
}

Try / catch

match create_index_result {
    Err(e) if e.to_string().contains("concatenate type must have at least one sub-field") => {
        eprintln!("List concatenate_fields or enable include_dynamic_fields");
    }
    other => other?,
}

Prevention

When it happens

Trigger: A mapping like `{name: "all", type: "concatenate", concatenate_fields: [], include_dynamic_fields: false}` — FieldMappingType::Concatenate deserialization bails.

Common situations: Setting up a 'search everything' concatenate field but forgetting to list fields; auto-generated mappings with empty lists when the intended default was include_dynamic_fields=true; field names removed from the list leaving it empty.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/c2c4f8058d6dbf99. Report an issue: GitHub.