quickwit-oss/quickwit · error

invalid 2nd argument for `hash_mod`: expected number

Error message

invalid 2nd argument for `hash_mod`: expected number

What it means

While converting the routing expression AST in `convert_ast`, the `hash_mod(...)` function was given a second argument that is not a number literal. `hash_mod` requires exactly two arguments: a field path and a numeric modulus, so the parser rejects the malformed expression.

Source

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

                    .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 {
        Ok(result.remove(0))
    } else {
        Ok(InnerRoutingExpr::Composite(result))
    }

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Use a bare integer as the second argument: `hash_mod(tenant_id, 4)`.
  2. Remove surrounding quotes from the modulo value in the config.
  3. Double-check the argument order: expression first, plain number second.

Example fix

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

Strategy: validation

Validate before calling

fn validate_hash_mod_modulo(args: &[Argument]) -> Result<(), String> {
    match args.get(1) {
        Some(Argument::Number(n)) if *n > 0 => Ok(()),
        _ => Err("second hash_mod argument must be a number".into()),
    }
}

Type guard

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

Prevention

When it happens

Trigger: Calling `RoutingExpr::from_str` with `hash_mod(tenant_id, tenant_id)` or `hash_mod(tenant_id, "4")` — the second argument is not a numeric literal.

Common situations: Quoting the modulo value; accidentally passing a second field name; generating routing expressions programmatically and inserting the modulo as a string.

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