jaegertracing/jaeger · error

search depth %d exceeds maximum allowed %d

Error message

search depth %d exceeds maximum allowed %d

What it means

buildFindTraceIDsQuery validates the requested search depth against the repository's MaxSearchDepth configuration before constructing the trace-ID lookup SQL. The search depth caps how many spans are scanned per trace during the search, and requests beyond the configured ceiling are rejected.

Source

Thrown at internal/storage/v2/clickhouse/tracestore/query_builder.go:131

	return q.String(), args
}

func buildFindTracesQuery(traceIDsQuery string) string {
	inner := indentBlock("SELECT trace_id FROM (\n" + indentBlock(strings.TrimSpace(traceIDsQuery)) + "\n)")
	base := strings.TrimRight(sql.SelectSpansQuery, "\n")
	return base + "\nWHERE s.trace_id IN (\n" + inner + "\n)\nORDER BY s.trace_id"
}

func (r *Reader) buildFindTraceIDsQuery(
	ctx context.Context,
	query tracestore.TraceQueryParams,
) (string, []any, error) {
	limit := query.SearchDepth
	if limit == 0 {
		limit = r.config.DefaultSearchDepth
	}
	if limit > r.config.MaxSearchDepth {
		return "", nil, fmt.Errorf("search depth %d exceeds maximum allowed %d", limit, r.config.MaxSearchDepth)
	}

	// Build the inner subquery that finds distinct trace IDs from spans.
	var inner strings.Builder
	inner.WriteString(sql.SearchTraceIDsBase)
	args := []any{}

	if query.ServiceName != "" {
		appendAnd(&inner, "s.service_name = ?")
		args = append(args, query.ServiceName)
	}
	if query.OperationName != "" {
		appendAnd(&inner, "s.name = ?")
		args = append(args, query.OperationName)
	}
	if query.DurationMin > 0 {
		appendAnd(&inner, "s.duration >= ?")
		args = append(args, query.DurationMin.Nanoseconds())

View on GitHub (pinned to 806f444784)

Solutions

  1. Lower the query's SearchDepth to at most MaxSearchDepth
  2. Leave SearchDepth at 0 so the configured DefaultSearchDepth is used
  3. Raise MaxSearchDepth in the storage configuration if deep searches are legitimate
  4. Align client and server search-depth settings

Example fix

// before
query.SearchDepth = 500 // exceeds MaxSearchDepth=100
// after
query.SearchDepth = 0 // use server DefaultSearchDepth
// or raise config:
// config.MaxSearchDepth = 500
Defensive patterns

Strategy: validation

Validate before calling

if query.SearchDepth > repo.Config().MaxSearchDepth {
    query.SearchDepth = repo.Config().MaxSearchDepth
}
if query.SearchDepth == 0 {
    query.SearchDepth = repo.Config().DefaultSearchDepth
}

Try / catch

traceIDs, err := store.FindTraceIDs(ctx, query)
var depthErr error
if errors.As(err, &depthErr) && strings.Contains(err.Error(), "exceeds maximum allowed") {
    query.SearchDepth = 0 // fall back to default
    traceIDs, err = store.FindTraceIDs(ctx, query)
}

Prevention

When it happens

Trigger: Calling the query builder (via FindTraceIDs) with a query whose SearchDepth is larger than the configured MaxSearchDepth, or a non-zero SearchDepth supplied by a client that exceeds the server's limit.

Common situations: A client hard-coding a large search depth while the ClickHouse store was configured with a conservative MaxSearchDepth; config drift between services sharing one storage backend.

Related errors


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