jaegertracing/jaeger · error
trace not found
Error message
trace not found
What it means
The get_span_details MCP handler looks up a trace by ID and filters its spans by the requested span IDs. This error is thrown when GetTraces returns no trace matching the requested trace ID (traceFound remains false), so there are no spans to inspect.
Source
Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/get_span_details.go:102
traceFound = true
// Iterate through all spans in the trace
for pos, span := range jptrace.SpanIter(trace) {
spanIDStr := span.SpanID().String()
// Check if this span ID is in the requested set
if _, found := spanIDSet[spanIDStr]; found {
detail := buildSpanDetail(pos, span)
spanDetails = append(spanDetails, detail)
// Remove from set to track which spans we've found
delete(spanIDSet, spanIDStr)
}
}
}
if !traceFound {
return nil, types.GetSpanDetailsOutput{}, errors.New("trace not found")
}
output := types.GetSpanDetailsOutput{
TraceID: input.TraceID,
Spans: spanDetails,
}
// Report any span IDs that were not found
if len(spanIDSet) > 0 {
missingIDs := make([]string, 0, len(spanIDSet))
for spanID := range spanIDSet {
missingIDs = append(missingIDs, spanID)
}
output.Error = fmt.Sprintf("spans not found: %v", missingIDs)
}
return nil, output, nil
}View on GitHub (pinned to 806f444784)
Solutions
- Confirm the trace exists via a plain trace lookup before requesting span details
- Check storage backend, tenant, and retention settings match where the trace was ingested
- Re-check the trace ID for typos (all 32 hex chars)
- Re-ingenerate/re-send the trace if sampling dropped it
Example fix
// before
out, err := spanDetails.Handle(ctx, req, types.GetSpanDetailsInput{TraceID: id, SpanIDs: ids})
// after
if _, lookupErr := getTrace.Handle(ctx, req, types.GetTraceInput{TraceID: id}); lookupErr != nil {
return nil, fmt.Errorf("cannot fetch span details: trace %s unavailable: %w", id, lookupErr)
}
out, err := spanDetails.Handle(ctx, req, types.GetSpanDetailsInput{TraceID: id, SpanIDs: ids}) Defensive patterns
Strategy: validation
Validate before calling
func validateSpanDetailsInput(in types.GetSpanDetailsInput) error {
if in.TraceID == "" { return errors.New("trace_id required") }
if _, err := hex.DecodeString(in.TraceID); err != nil { return fmt.Errorf("bad trace_id: %w", err) }
if len(in.SpanIDs) == 0 { return errors.New("span_ids required") }
return nil
} Try / catch
out, err := handler.Handle(ctx, req, input)
if err != nil {
if strings.Contains(err.Error(), "trace not found") {
return fmt.Errorf("trace %s unavailable; check retention/sampling/backend", input.TraceID)
}
return err
} Prevention
- Confirm trace existence with a plain lookup before filtered span queries
- Canonicalize span IDs to lowercase hex and drop zero values
- Match the storage backend/tenant used at ingestion time
When it happens
Trigger: Calling get_span_details with a trace_id that does not exist in storage, or whose spans exist only in a different backend; the query returns zero iterations so traceFound never becomes true.
Common situations: Trace expired from retention; sampling prevented storage; wrong environment/tenant's trace ID; trace ID mistyped; replicas lagging behind the writer.
Related errors
- trace not found
- trace not found
- failed to get dependencies: %w
- failed to get services: %w
- failed to get trace: %w
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/09df9b276affab11.
Report an issue: GitHub.