jaegertracing/jaeger · error
%w: it compares %q against a duration such as "2s" only
Error message
%w: it compares %q against a duration such as "2s" only
What it means
A bound on the span.duration built-in field must be a *expression.DurationValue (a length of time such as "2s"). When the constant is neither a DurationValue nor an untyped AnyValue (that case yields ErrFilterInvalid instead), the comparison asks for a value type durations cannot have — a number or string constant — and is refused with ErrFilterUnsupported. This guards the legacy duration fields DurationMin/DurationMax from being assigned non-duration constants.
Source
Thrown at internal/storage/v2/api/tracestore/shape.go:282
switch constant := value.(type) {
case *expression.StringValue:
return constant.Value, nil
case *expression.AnyValue:
return constant.Value, nil
default:
return "", fmt.Errorf("%w: it compares %q against a string constant only", ErrFilterUnsupported, name)
}
}
// errNotADuration refuses a bound that is not a length of time. An untyped constant reaching here
// was never read as a duration, which expression.ResolveConstants does on the way in, so the
// refusal says that rather than blaming the spelling the caller wrote.
func errNotADuration(name string, value expression.Expression) error {
if constant, ok := value.(*expression.AnyValue); ok {
return fmt.Errorf("%w: the bound %q on %q was never read as a duration",
ErrFilterInvalid, constant.Value, name)
}
return fmt.Errorf(`%w: it compares %q against a duration such as "2s" only`,
ErrFilterUnsupported, name)
}
func errUnsupportedOperator(op expression.Operator) error {
return fmt.Errorf("%w: it does not support the operator %q", ErrFilterUnsupported, op)
}
func errUnsupportedOperatorOn(op expression.Operator, name string) error {
return fmt.Errorf("%w: it does not support the operator %q on %q", ErrFilterUnsupported, op, name)
}
func errRepeatedPredicateOn(name string) error {
return fmt.Errorf("%w: it can carry only one predicate on %q", ErrFilterUnsupported, name)
}
View on GitHub (pinned to 806f444784)
Solutions
- Use a duration literal/spelling so ResolveConstants produces a *expression.DurationValue (e.g. "2s", "500ms").
- Construct the value explicitly as &expression.DurationValue{Value: d} from a time.Duration.
- Move the numeric comparison to an attribute predicate or a backend with native typed filter support.
Example fix
// before
&expression.Call{Op: expression.OpGte, Args: []expression.Expression{durField, &expression.Int64Value{Value: 2000}}}
// after
&expression.Call{Op: expression.OpGte, Args: []expression.Expression{durField, &expression.DurationValue{Value: 2 * time.Second}}} Defensive patterns
Strategy: validation
Validate before calling
func durationBoundFromString(s string) (*expression.DurationValue, error) {
d, err := time.ParseDuration(s)
if err != nil { return nil, err }
return &expression.DurationValue{Value: d}, nil
} Type guard
func isDurationValue(v expression.Expression) bool { _, ok := v.(*expression.DurationValue); return ok } Try / catch
legacy, err := params.ToLegacyShape()
if errors.Is(err, tracestore.ErrFilterUnsupported) {
return fmt.Errorf("duration bounds must be durations like \"2s\", not numbers or strings: %w", err)
} Prevention
- Express duration bounds with duration literals ("2s", "500ms")
- Convert numeric milliseconds to time.Duration before building the predicate
- Validate predicate value types against the field's declared type before querying
When it happens
Trigger: ToLegacyShape() downconversion sees span.duration >=/<= with a typed constant that is not a duration, e.g. a StringValue{"2s"} or numeric constant on the duration field.
Common situations: A client writes duration > 1000 (number) instead of duration > 1s; a UI sends the bound as a plain string constant; mismatched expression construction helpers.
Related errors
- %w: it does not support the built-in field %q of the %q leve
- %w: it compares %q against a string constant only
- %w: it does not support the operator %q
- %w: it does not support the operator %q on %q
- %w: it can carry only one predicate on %q
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/59fa8fd79436b263.
Report an issue: GitHub.