jaegertracing/jaeger · warning

api_v3 does not expose the backend's search capabilities: %w

Error message

api_v3 does not expose the backend's search capabilities: %w

What it means

traceReader.SearchCapabilities must report what search predicates the underlying storage supports, but api_v3 has no capability-discovery RPC, so the client cannot learn what the remote query service supports. Rather than guess, it returns the zero tracestore.SearchCapabilities wrapped with errors.ErrUnsupported and the message 'api_v3 does not expose the backend's search capabilities'.

Source

Thrown at cmd/jaeger/internal/integration/trace_reader.go:50

var (
	_ tracestore.Reader = (*traceReader)(nil)
	_ io.Closer         = (*traceReader)(nil)
)

// traceReader retrieves trace data from the jaeger-v2 query service through the api_v2.QueryServiceClient.
type traceReader struct {
	logger     *zap.Logger
	clientConn *grpc.ClientConn
	client     api_v3.QueryServiceClient
}

// SearchCapabilities cannot be answered: api_v3 has no capability discovery, so this
// client has no way to ask the query service what the storage behind it supports
// (RFC 0013 §3.7 proposes the API that would let it). Reporting ErrUnsupported says
// exactly that, where any concrete value would be a guess a caller might trust.
func (*traceReader) SearchCapabilities(context.Context) (tracestore.SearchCapabilities, error) {
	return tracestore.SearchCapabilities{}, fmt.Errorf(
		"api_v3 does not expose the backend's search capabilities: %w", errors.ErrUnsupported,
	)
}

func createTraceReader(logger *zap.Logger, port int) (*traceReader, error) {
	logger.Info("Creating the trace reader", zap.Int("port", port))
	opts := []grpc.DialOption{
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	}

	cc, err := grpc.NewClient(ports.PortToHostPort(port), opts...)
	if err != nil {
		return nil, err
	}

	return &traceReader{
		logger:     logger,
		clientConn: cc,

View on GitHub (pinned to 806f444784)

Solutions

  1. Treat errors.ErrUnsupported as expected for api_v3 and use conservative/default search behavior
  2. Use a native tracestore Reader (e.g. direct storage backend) instead of the api_v3 remote reader if capabilities matter
  3. Adopt the capability-discovery API proposed in RFC 0013 §3.7 once available

Example fix

// before
caps, err := reader.SearchCapabilities(ctx)
if err != nil { return err }
// after
caps, err := reader.SearchCapabilities(ctx)
if errors.Is(err, errors.ErrUnsupported) {
    caps = tracestore.SearchCapabilities{} // assume minimal support
} else if err != nil { return err }
Defensive patterns

Strategy: fallback

Validate before calling

// capability probe
caps, err := reader.SearchCapabilities(ctx)
supportsMaxDuration := err == nil && caps.MaxDuration

Try / catch

caps, err := reader.SearchCapabilities(ctx)
switch {
case err == nil:
    useCaps(caps)
case errors.Is(err, errors.ErrUnsupported): // api_v3 reader
    useCaps(tracestore.SearchCapabilities{}) // conservative defaults
default:
    return err
}

Prevention

When it happens

Trigger: Any call to SearchCapabilities on the api_v3-based traceReader (used by e2e integration tests driving jaeger over the wire) — unconditionally returns this error.

Common situations: Test frameworks or code probing search capabilities of a remote jaeger reached through api_v3; capability-adaptive callers that skip unsupported predicates will always take their 'unsupported' path with this backend.

Related errors


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