jaegertracing/jaeger · error
invalid trace_id: %w
Error message
invalid trace_id: %w
What it means
buildQuery parses input.TraceID with parseTraceID, which requires a 32-character hex string representing a 16-byte pcommon.TraceID. Any parse failure (wrong length or non-hex characters) is wrapped as "invalid trace_id" so the caller knows the identifier itself is malformed.
Source
Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/get_span_details.go:145
return querysvc.GetTraceParams{}, nil, errors.New("trace_id is required")
}
if len(input.SpanIDs) == 0 {
return querysvc.GetTraceParams{}, nil, errors.New("span_ids is required and must not be empty")
}
// Validate span count against configured limit
if len(input.SpanIDs) > h.maxSpanDetailsPerRequest {
return querysvc.GetTraceParams{}, nil, fmt.Errorf(
"span_ids exceeds maximum limit: requested %d, max allowed %d",
len(input.SpanIDs),
h.maxSpanDetailsPerRequest,
)
}
traceID, err := parseTraceID(input.TraceID)
if err != nil {
return querysvc.GetTraceParams{}, nil, fmt.Errorf("invalid trace_id: %w", err)
}
// Validate every span_id up front so a malformed value fails fast instead of
// triggering a backend query that can never match a real span ID. Collect the
// canonical lowercase hex form so the lookup set agrees with the ID the trace
// iterator emits regardless of the request's casing.
canonicalSpanIDs := make([]string, 0, len(input.SpanIDs))
for _, spanIDStr := range input.SpanIDs {
spanID, err := parseSpanID(spanIDStr)
if err != nil {
return querysvc.GetTraceParams{}, nil, fmt.Errorf("invalid span_id %q: %w", spanIDStr, err)
}
canonicalSpanIDs = append(canonicalSpanIDs, spanID.String())
}
return querysvc.GetTraceParams{
TraceIDs: []tracestore.GetTraceParams{
{TraceID: traceID},View on GitHub (pinned to 806f444784)
Solutions
- Provide the full 32-character lowercase hex trace ID, e.g. "4bf92f3577b34da6a3ce929d0e0e4736".
- Left-pad 16-hex-char legacy IDs with zeros to 32 characters.
- Strip any "0x" prefix, dashes, or whitespace before calling the tool.
- Confirm you are not passing a span ID where trace_id is expected.
Example fix
// before TraceID: "4bf92f3577b34da6" // 16 chars // after TraceID: "00000000000000004bf92f3577b34da6" // padded to 32 hex chars
Defensive patterns
Strategy: validation
Validate before calling
func validTraceID(s string) bool {
if len(s) != 32 { return false }
_, err := hex.DecodeString(s)
return err == nil
} Type guard
func normalizeTraceID(s string) (string, bool) {
s = strings.TrimPrefix(strings.TrimSpace(s), "0x")
if len(s) < 16 || len(s) > 32 { return "", false }
if _, err := hex.DecodeString(s); err != nil { return "", false }
return fmt.Sprintf("%032s", s), true
} Try / catch
out, _, err := handler.Handle(ctx, req, input)
if err != nil && strings.HasPrefix(err.Error(), "invalid trace_id") {
id, ok := normalizeTraceID(input.TraceID)
if !ok { return err }
input.TraceID = id
out, _, err = handler.Handle(ctx, req, input)
} Prevention
- Always pass 32-char lowercase hex trace IDs.
- Left-pad 16-char legacy IDs with zeros to 32 chars.
- Strip 0x prefixes, dashes, and whitespace at ingestion into your client.
- Never reuse a span ID in the trace_id field.
When it happens
Trigger: Passing a 16-character (8-byte) legacy-style ID without padding, an ID containing '0x' prefix or dashes, a decimal-formatted ID, or an empty string, to the get_span_details tool.
Common situations: Mixing IDs from systems using 64-bit span/trace IDs (W3C 8-byte traces) with Jaeger's 128-bit format; copying IDs from logs with formatting applied; a client passing a span ID into the trace_id field.
Related errors
- trace_id is required
- start_time must be before end_time
- trace_id is required
- span_ids is required and must not be empty
- span ID must not be all zero
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/e7b52fc24986e1b9.
Report an issue: GitHub.