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

  1. Confirm the trace exists via a plain trace lookup before requesting span details
  2. Check storage backend, tenant, and retention settings match where the trace was ingested
  3. Re-check the trace ID for typos (all 32 hex chars)
  4. 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

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


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