{"record":{"id":"81342b9a463636b0","repo":"jaegertracing/jaeger","slug":"w-w","errorCode":null,"errorMessage":"%w: %w","messagePattern":"%w: %w","errorType":"exception","errorClass":"ErrInterceptorFilter","httpStatus":null,"severity":"error","filePath":"cmd/jaeger/internal/extension/jaegerquery/querysvc/interceptor.go","lineNumber":111,"sourceCode":"// not hand to storage. An interceptor builds its filter by hand, in code jaeger-query does not\n// control, and a malformed tree is typically answered by a backend matching nothing rather than\n// refusing — so a search meant to be narrowed would come back wrong with nothing to say why.\n//\n// It finalizes rather than only validates, so that an interceptor's predicate reaches storage as the\n// equal of one a caller sent, having been through the same stage.\n//\n// A nil filter here is the one mistake that fails open: a search that arrived with predicates and\n// leaves with none asks for every trace in the time range. Its caller returns before this point when\n// there were no predicates to begin with, since a caller may legitimately search a time range and\n// nothing else.\nfunc finalizeInterceptorFilter(returned *expression.Call) (*expression.Call, error) {\n\tif returned == nil {\n\t\treturn nil, fmt.Errorf(\"%w: it returned no filter for a query that had predicates, which \"+\n\t\t\t\"would widen the search to every trace in the time range\", ErrInterceptorFilter)\n\t}\n\tfinalized, err := expression.Finalize(returned)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w: %w\", ErrInterceptorFilter, err)\n\t}\n\treturn finalized, nil\n}\n\n// interceptResults hands every batch of seq to the interceptors' OnResult in order, threading the\n// context each returns into the next so that state can accumulate across a multi-batch result.\n// An OnResult error ends the stream rather than yielding later batches, which could leak results\n// the failed sanitize or redaction was meant to withhold.\n//\n// It wraps the batches as storage yielded them, before the query service aggregates and adjusts\n// them, so an interceptor rewrites the traces the reader actually returned.\nfunc (qs QueryService) interceptResults(\n\tctx context.Context,\n\tseq iter.Seq2[[]ptrace.Traces, error],\n) iter.Seq2[[]ptrace.Traces, error] {\n\tif len(qs.options.Interceptors) == 0 {\n\t\treturn seq\n\t}","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/cmd/jaeger/internal/extension/jaegerquery/querysvc/interceptor.go#L93-L129","documentation":"ErrInterceptorFilter is wrapped when expression.Finalize fails on the filter returned by a query interceptor. Finalize validates and normalizes the expression; a failure means the interceptor produced a structurally invalid or ill-typed filter that Jaeger cannot compile into a storage query. The original Finalize error is chained via Go's multi-%w wrapping for errors.Is/As inspection.","triggerScenarios":"finalizeInterceptorFilter calls expression.Finalize(returned) on the interceptor's returned *expression.Call and Finalize returns an error — e.g. the interceptor built a Call with a wrong argument count, an unknown function, or mismatched operand types.","commonSituations":"Custom interceptor composing expression AST nodes by hand with incorrect types or arity; an interceptor forwarding a stale/partially built expression; version skew where the expression API changed shape between Jaeger versions.","solutions":["Inspect the chained Finalize error in the message for the exact structural problem.","Fix the interceptor to build the filter using the expression package's public constructors only.","Have the interceptor validate its expression (Finalize) itself before returning it to fail fast locally.","Rebuild against the jaeger version in use if the expression API changed underneath."],"exampleFix":"// before\nreturn expression.NewCall(customFn, operandOfWrongType), nil\n// after\nreturn expression.NewCall(expression.EqFn, expression.NewStringField(\"service.name\"), expression.NewStringLiteralValue(\"foo\")), nil","handlingStrategy":"try-catch","validationCode":"// inside interceptor before returning\nif _, err := expression.Finalize(myCall); err != nil {\n    return nil, fmt.Errorf(\"interceptor built invalid expression: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && errors.Is(err, querysvc.ErrInterceptorFilter) {\n    var finErr error\n    if errors.As(err, &finErr) {\n        log.Printf(\"finalize failed inside interceptor filter: %v\", finErr)\n    }\n    return err\n}","preventionTips":["Build expressions only with the expression package's typed constructors.","Self-validate interceptor output with Finalize in its own tests.","Keep interceptor and jaeger versions in lockstep."],"tags":["interceptor","expression","validation","query-filter"],"backgroundTag":"interceptor-invalid-filter","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}