quickwit-oss/quickwit · error

invalid 1st argument for `hash_mod`: expected expression

Error message

invalid 1st argument for `hash_mod`: expected expression

What it means

After checking `hash_mod` arity, `convert_ast` removes the first argument and requires it to be an `Argument::Expression`. If the first argument is not an expression (e.g. a plain number or identifier value), this error is thrown.

Source

Thrown at quickwit/quickwit-doc-mapper/src/routing_expression/mod.rs:299

        .map(|ast_elem| match ast_elem {
            ExpressionAst::Field(field_name) => {
                let field_path = expression_dsl::parse_field_name(&field_name)?
                    .into_iter()
                    .map(Cow::into_owned)
                    .collect();
                Ok(InnerRoutingExpr::Field(field_path))
            }
            ExpressionAst::Function { name, mut args } => match &*name {
                "hash_mod" => {
                    if args.len() != 2 {
                        anyhow::bail!(
                            "invalid arguments for `hash_mod`: expected 2 arguments, found {}",
                            args.len()
                        );
                    }

                    let Argument::Expression(fields) = args.remove(0) else {
                        anyhow::bail!("invalid 1st argument for `hash_mod`: expected expression");
                    };

                    let Argument::Number(modulo) = args.remove(0) else {
                        anyhow::bail!("invalid 2nd argument for `hash_mod`: expected number");
                    };

                    Ok(InnerRoutingExpr::Modulo(
                        Box::new(convert_ast(fields)?),
                        modulo,
                    ))
                }
                _ => anyhow::bail!("unknown function `{}`", name),
            },
        })
        .collect::<Result<Vec<_>, _>>()?;
    if result.is_empty() {
        Ok(InnerRoutingExpr::default())
    } else if result.len() == 1 {

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Pass a field-path expression as the first argument: `hash_mod(tenant_id, 4)`.
  2. Ensure the field name is not quoted or reduced to a number literal in the routing expression.
  3. Verify the order of arguments — expression first, modulo number second.

Example fix

// before
routing_expression: hash_mod(4, tenant_id)
// after
routing_expression: hash_mod(tenant_id, 4)
Defensive patterns

Strategy: validation

Validate before calling

fn validate_hash_mod_args(args: &[Argument]) -> Result<(), String> {
    match args.first() {
        Some(Argument::Expression(_)) => Ok(()),
        _ => Err("first hash_mod argument must be an expression".into()),
    }
}

Type guard

fn is_expression(a: &Argument) -> bool { matches!(a, Argument::Expression(_)) }

Try / catch

match RoutingExpr::from_str(cfg.routing_expression.as_str()) {
    Ok(expr) => expr,
    Err(e) if e.to_string().contains("hash_mod") => return Err(ConfigError::Routing(e)),
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling `RoutingExpr::from_str` with `hash_mod(10, 4)` or otherwise passing a non-expression (number/other literal) as the first argument of `hash_mod`.

Common situations: Swapping the two arguments (`hash_mod(4, tenant_id)`); quoting/escaping issues that turn a field path into a literal; misunderstanding that the first argument must be a field-path expression.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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