quickwit-oss/quickwit · error

fields and default_field cannot be both set in `query_string

Error message

fields and default_field cannot be both set in `query_string` queries

What it means

In QueryStringQuery::convert_to_query_ast, the Elastic-compatible `query_string` query rejects requests that supply both `default_field` (single field) and `fields` (list of fields). These two options are alternative ways to scope the search, so setting both is ambiguous and is treated as an invalid request. Either omit one, or use only `fields` with a single-element list.

Source

Thrown at quickwit/quickwit-query/src/elastic_query_dsl/query_string_query.rs:46

    /// We do not support JSON field either.
    ///
    /// Note that following elastic, we do not support "string" and require an array here.
    #[serde(default)]
    fields: Option<Vec<String>>,
    #[serde(default)]
    default_field: Option<String>,
    #[serde(default)]
    default_operator: BooleanOperand,
    #[serde(default)]
    boost: Option<NotNaNf32>,
    #[serde(default)]
    lenient: LeniencyBool,
}

impl ConvertibleToQueryAst for QueryStringQuery {
    fn convert_to_query_ast(self) -> anyhow::Result<crate::query_ast::QueryAst> {
        if self.default_field.is_some() && self.fields.is_some() {
            anyhow::bail!("fields and default_field cannot be both set in `query_string` queries");
        }
        let default_fields: Option<Vec<String>> = self
            .default_field
            .map(|default_field| vec![default_field])
            .or(self.fields);
        let user_text_query = UserInputQuery {
            user_text: self.query,
            default_fields,
            default_operator: self.default_operator,
            lenient: self.lenient,
        };
        Ok(user_text_query.into())
    }
}

#[cfg(test)]
mod tests {
    use crate::BooleanOperand;

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Remove `default_field` and keep only `fields` (list) when targeting multiple fields.
  2. Remove `fields` and keep only `default_field` when targeting a single field.
  3. If a single field is intended, move it into `fields` as a one-element list and drop `default_field`.
  4. Check client/library defaults that may inject `default_field` automatically.

Example fix

// before
{"query_string": {"query": "error", "default_field": "message", "fields": ["message", "level"]}}
// after
{"query_string": {"query": "error", "fields": ["message", "level"]}}
Defensive patterns

Strategy: validation

Validate before calling

if qs.default_field.is_some() && qs.fields.is_some() {
    return Err("query_string: provide either default_field or fields, not both");
}

Try / catch

match parse_and_build(query) {
    Err(e) if e.to_string().contains("cannot be both set") => {
        // retry with fields only
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling convert_to_query_ast (e.g. via the query_string DSL or REST API with query_string queries) when both `default_field` and `fields` are set to Some, such as `{"query_string": {"query": "foo", "default_field": "body", "fields": ["title", "body"]}}`.

Common situations: Mixing Elasticsearch client libraries that set `default_field` by default while the user also passes `fields`; copying ES examples that use both; migrating from simple single-field queries to multi-field queries without removing the old `default_field` parameter.

Related errors


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