{"record":{"id":"59fa8fd79436b263","repo":"jaegertracing/jaeger","slug":"w-it-compares-q-against-a-duration-such-as-2s","errorCode":null,"errorMessage":"%w: it compares %q against a duration such as \"2s\" only","messagePattern":"%w: it compares %q against a duration such as \"2s\" only","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/v2/api/tracestore/shape.go","lineNumber":282,"sourceCode":"\tswitch constant := value.(type) {\n\tcase *expression.StringValue:\n\t\treturn constant.Value, nil\n\tcase *expression.AnyValue:\n\t\treturn constant.Value, nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"%w: it compares %q against a string constant only\", ErrFilterUnsupported, name)\n\t}\n}\n\n// errNotADuration refuses a bound that is not a length of time. An untyped constant reaching here\n// was never read as a duration, which expression.ResolveConstants does on the way in, so the\n// refusal says that rather than blaming the spelling the caller wrote.\nfunc errNotADuration(name string, value expression.Expression) error {\n\tif constant, ok := value.(*expression.AnyValue); ok {\n\t\treturn fmt.Errorf(\"%w: the bound %q on %q was never read as a duration\",\n\t\t\tErrFilterInvalid, constant.Value, name)\n\t}\n\treturn fmt.Errorf(`%w: it compares %q against a duration such as \"2s\" only`,\n\t\tErrFilterUnsupported, name)\n}\n\nfunc errUnsupportedOperator(op expression.Operator) error {\n\treturn fmt.Errorf(\"%w: it does not support the operator %q\", ErrFilterUnsupported, op)\n}\n\nfunc errUnsupportedOperatorOn(op expression.Operator, name string) error {\n\treturn fmt.Errorf(\"%w: it does not support the operator %q on %q\", ErrFilterUnsupported, op, name)\n}\n\nfunc errRepeatedPredicateOn(name string) error {\n\treturn fmt.Errorf(\"%w: it can carry only one predicate on %q\", ErrFilterUnsupported, name)\n}\n","sourceCodeStart":264,"sourceCodeEnd":297,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/internal/storage/v2/api/tracestore/shape.go#L264-L297","documentation":"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.","triggerScenarios":"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.","commonSituations":"A client writes duration > 1000 (number) instead of duration > 1s; a UI sends the bound as a plain string constant; mismatched expression construction helpers.","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."],"exampleFix":"// before\n&expression.Call{Op: expression.OpGte, Args: []expression.Expression{durField, &expression.Int64Value{Value: 2000}}}\n// after\n&expression.Call{Op: expression.OpGte, Args: []expression.Expression{durField, &expression.DurationValue{Value: 2 * time.Second}}}","handlingStrategy":"validation","validationCode":"func durationBoundFromString(s string) (*expression.DurationValue, error) {\n  d, err := time.ParseDuration(s)\n  if err != nil { return nil, err }\n  return &expression.DurationValue{Value: d}, nil\n}","typeGuard":"func isDurationValue(v expression.Expression) bool { _, ok := v.(*expression.DurationValue); return ok }","tryCatchPattern":"legacy, err := params.ToLegacyShape()\nif errors.Is(err, tracestore.ErrFilterUnsupported) {\n  return fmt.Errorf(\"duration bounds must be durations like \\\"2s\\\", not numbers or strings: %w\", err)\n}","preventionTips":["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"],"tags":["jaeger","tracestore","filter-unsupported","duration-type"],"backgroundTag":"unsupported-comparison-type","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}