OrchardCMS/OrchardCore · error · ArgumentException
Lower and upper bound range types don't match
Error message
Lower and upper bound range types don't match
What it means
RangeQueryProvider.CreateQuery supports range queries where the lower (gt/gte) and upper (lt/lte) bounds are of the same JSON type (both numbers or both strings). If both bounds are present but their JSON value kinds differ, e.g. a number lower bound with a string upper bound, it throws ArgumentException because Lucene range queries need homogeneous bound types.
Solutions
- Make both bounds the same JSON type — quote both or unquote both, e.g. {"gt": "5", "lt": "10"} or {"gt": 5, "lt": 10}.
- If the field is a date/text field, express both bounds as strings; if numeric, both as numbers.
- Normalize bound values in the code that assembles the query before calling CreateQuery.
Example fix
// before
{"Price": {"type": "range", "gt": 10, "lt": "100"}}
// after
{"Price": {"type": "range", "gt": 10, "lt": 100}} Defensive patterns
Strategy: validation
Validate before calling
var gt = obj["gt"] ?? obj["gte"]; var lt = obj["lt"] ?? obj["lte"]; if (gt != null && lt != null && gt.GetValueKind() != lt.GetValueKind()) throw new InvalidOperationException("Range bounds must share the same JSON type"); Type guard
static bool BoundsKindMatch(JsonNode obj) { var g = obj["gt"] ?? obj["gte"]; var l = obj["lt"] ?? obj["lte"]; return g == null || l == null || g.GetValueKind() == l.GetValueKind(); } Try / catch
try { var q = provider.CreateQuery(node); } catch (ArgumentException ex) when (ex.Message.Contains("range types don't match")) { // coerce both bounds to a common type and retry } Prevention
- Normalize numeric bounds to unquoted numbers and text/date bounds to quoted strings.
- Build both bounds from the same typed variable in query-builder code.
- Add a pre-submit validation step for range filters in the UI.
When it happens
Trigger: A range node like {"field": {"type": "range", "gt": 5, "lt": "10"}} — gt is a number but lt is a string, so GetValueKind() differs.
Common situations: Mixing quoted and unquoted numbers in hand-edited query JSON; dates given as strings with numeric bounds; query built by concatenating user-supplied filters of different types.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Lower and upper bound range types don't match
- Unsupported range value type
- Invalid range query
- Unsupported range value type
- Invalid range query
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/5aa7f76776eaeaa1.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore/OrchardCore.Lucene.Core/QueryProviders/RangeQueryProvider.cs:61
break;
case "lt":
lt = element.Value;
nodeKind = lt.GetValueKind();
break;
case "lte":
lt = element.Value;
nodeKind = lt.GetValueKind();
includeUpper = true;
break;
case "boost":
boost = element.Value.Value<float>();
break;
}
}
if (gt != null && lt != null && gt.GetValueKind() != lt.GetValueKind())
{
throw new ArgumentException("Lower and upper bound range types don't match");
}
switch (nodeKind)
{
case JsonValueKind.Number:
if (gt.AsValue().TryGetValue<long>(out var minInt) &&
lt.AsValue().TryGetValue<long>(out var maxInt))
{
rangeQuery = NumericRangeQuery.NewInt64Range(field, minInt, maxInt, includeLower, includeUpper);
}
else if (gt.AsValue().TryGetValue<double>(out var minFloat) &&
lt.AsValue().TryGetValue<double>(out var maxFloat))
{
rangeQuery = NumericRangeQuery.NewDoubleRange(field, minFloat, maxFloat, includeLower, includeUpper);
}
else
{
throw new ArgumentException($"Unsupported range value type: {type}");View on GitHub (pinned to 4306c0717f)