jaegertracing/jaeger · error

: it does not support the operator on

Error message

%w: it does not support the operator %q on %q

What it means

The legacy fields a filter is downconverted into accept exactly one operator each: attributes, service name and operation name accept only equality (OpEq), and span.duration accepts only inclusive bounds OpGte/OpLte. Any other operator on that field — e.g. != on a tag, > on a name, < on a duration — has no legacy representation and is refused with ErrFilterUnsupported naming the operator and field. The narrower errUnsupportedOperator variant is used when no field name is known.

Solutions

  1. Rewrite as equality where possible (e.g. negate client-side, or use the exact matching value).
  2. Use inclusive bounds for duration: duration >= X / duration <= Y instead of strict > / <.
  3. Target a backend that declares native filter/operator support so no downconversion happens.

Example fix

// before
&expression.Call{Op: expression.OpGt, Args: []expression.Expression{durField, &expression.DurationValue{Value: time.Second}}}
// after
&expression.Call{Op: expression.OpGte, Args: []expression.Expression{durField, &expression.DurationValue{Value: time.Second}}}
Defensive patterns

Strategy: validation

Validate before calling

func allowedOp(op expression.Operator, ref expression.Expression) bool {
  switch ref.(type) {
  case *expression.AttributeRef:
    return op == expression.OpEq
  case *expression.FieldRef:
    fr := ref.(*expression.FieldRef)
    if fr.Name == expression.SpanFieldDuration {
      return op == expression.OpGte || op == expression.OpLte
    }
    return op == expression.OpEq
  }
  return false
}

Try / catch

legacy, err := params.ToLegacyShape()
if errors.Is(err, tracestore.ErrFilterUnsupported) {
  return nil, fmt.Errorf("legacy fields support only =, and >=/<= for duration: %w", err)
}

Prevention

When it happens

Trigger: ToLegacyShape() sees an AttributeRef predicate with op != OpEq; a service/name FieldRef predicate with op != OpEq; or a duration FieldRef predicate with an op other than OpGte/OpLte.

Common situations: Users write attribute != value or attribute > value searches in a UI; exclusive bounds duration > 1s are requested from a legacy backend; a filter builder emits regex-like operators unsupported by the legacy shape.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/311173b4364632b6. Report an issue: GitHub.

Appendix: source

Thrown at internal/storage/v2/api/tracestore/shape.go:291

// 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)