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
- Pass a field-path expression as the first argument: `hash_mod(tenant_id, 4)`.
- Ensure the field name is not quoted or reduced to a number literal in the routing expression.
- 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
- Pass the field path as the first hash_mod argument, never a literal.
- Lint routing expression configs for argument order before deployment.
- Document the signature hash_mod(<field-expr>, <number>) for config authors.
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
- invalid 2nd argument for `hash_mod`: expected number
- invalid arguments for `hash_mod`: expected 2 arguments, foun
- unknown function `{}`
- error parsing routing expression: {e}
- Facet are not supported in quickwit yet.
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/9af8943c7e48c269.
Report an issue: GitHub.