jaegertracing/jaeger · error

invalid span_id %q: %w

Error message

invalid span_id %q: %w

What it means

Each entry in input.SpanIDs is validated with parseSpanID before querying. A malformed span ID (wrong hex format or length) aborts the whole request with "invalid span_id \"<value>\": <reason>". The message quotes the offending value so the client can fix exactly that entry; validation happens up front to avoid a doomed backend query.

Source

Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/get_span_details.go:156

			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},
		},
		RawTraces: false, // We want adjusted traces
	}, canonicalSpanIDs, nil
}

// buildSpanDetail constructs a SpanDetail from a ptrace.Span.
func buildSpanDetail(pos jptrace.SpanIterPos, span ptrace.Span) types.SpanDetail {
	// Get service name from resource attributes
	serviceName := ""
	if svc, ok := pos.Resource.Resource().Attributes().Get("service.name"); ok {
		serviceName = svc.Str()

View on GitHub (pinned to 806f444784)

Solutions

  1. Fix the quoted span ID to be valid hex of the expected length.
  2. Remove or correct empty/placeholder entries in the span_ids array.
  3. Ensure IDs are passed as separate array elements, not a delimited string.
  4. Decode from the correct representation: span IDs in Jaeger API/OTLP are hex strings, not raw bytes or base64.

Example fix

// before
SpanIDs: ["abc", "7c4485"+"-01"]
// after
SpanIDs: ["bf39692569d65829", "7c44850100000000"]
Defensive patterns

Strategy: validation

Validate before calling

func validSpanID(s string) bool {
	if len(s) != 16 { return false } // pcommon.SpanID is 8 bytes
	_, err := hex.DecodeString(s)
	return err == nil
}
// filter: spanIDs = slices.DeleteFunc(spanIDs, func(id string) bool { return !validSpanID(id) })

Type guard

func normalizeSpanID(s string) (string, bool) {
	s = strings.TrimPrefix(strings.TrimSpace(s), "0x")
	if _, err := hex.DecodeString(s); err != nil || len(s) == 0 { return "", false }
	return strings.ToLower(s), true
}

Try / catch

out, _, err := handler.Handle(ctx, req, input)
if err != nil && strings.HasPrefix(err.Error(), "invalid span_id") {
	var bad string
	fmt.Sscanf(err.Error(), "invalid span_id %q", &bad)
	input.SpanIDs = slices.DeleteFunc(input.SpanIDs, func(id string) bool { return id == bad })
	out, _, err = handler.Handle(ctx, req, input)
}

Prevention

When it happens

Trigger: Calling get_span_details with any SpanIDs element that parseSpanID rejects: non-hex characters, empty string, wrong length for pcommon.SpanID, or an ID containing separators/prefixes.

Common situations: Span IDs copied from spans/JSON attributes that were already hex-decoded or base64-encoded; mixing 8-byte span IDs from other instrumentation with the expected format; list built by concatenating IDs with commas instead of separate array elements.

Related errors


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