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
- Lower the query's SearchDepth to at most MaxSearchDepth
- Leave SearchDepth at 0 so the configured DefaultSearchDepth is used
- Raise MaxSearchDepth in the storage configuration if deep searches are legitimate
- 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
- Leave SearchDepth unset (0) unless deep search is required
- Read MaxSearchDepth from config before setting SearchDepth
- Keep client and server search-depth configs aligned
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
- unsupported attribute type %v for key %s
- ttl must be a non-negative duration
- ttl must be a whole number of seconds
- default_search_depth must be a positive number
- max_search_depth must be a positive number
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/f29025ef369727cf.
Report an issue: GitHub.