jaegertracing/jaeger · error
span ID must not be all zero
Error message
span ID must not be all zero
What it means
parseSpanID decodes a hex span ID into pcommon.SpanID and rejects the all-zero value, because SpanID.String() renders it as "" and it would silently never match any real span during the filtered lookup. This guard turns a silent no-match into an explicit input error.
Source
Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/get_span_details.go:305
// parseSpanID parses a span ID string into a pcommon.SpanID.
func parseSpanID(spanIDStr string) (pcommon.SpanID, error) {
// Parse hex string - SpanID is 8 bytes (16 hex characters)
if len(spanIDStr) != 16 {
return pcommon.SpanID{}, fmt.Errorf("span ID must be 16 hex characters, got %d", len(spanIDStr))
}
var spanID pcommon.SpanID
bytes, err := hex.DecodeString(spanIDStr)
if err != nil {
return pcommon.SpanID{}, fmt.Errorf("invalid hex string: %w", err)
}
copy(spanID[:], bytes)
// The all-zero span ID can never identify a real span: SpanID.String()
// returns "" for it, so it would silently never match in the lookup.
if spanID.IsEmpty() {
return pcommon.SpanID{}, errors.New("span ID must not be all zero")
}
return spanID, nil
}
View on GitHub (pinned to 806f444784)
Solutions
- Replace the zero span ID with the real span ID from the trace's span metadata
- Filter out all-zero span IDs client-side before calling the tool
- Fix the upstream producer that emitted a zero SpanID (usually an unset field in an exported trace)
Example fix
// before
ids := []string{span.ID().String()} // may be "0000000000000000" if span unset
// after
var filtered []string
for _, id := range candidateIDs {
if id != "0000000000000000" && strings.Trim(id, "0") != "" {
filtered = append(filtered, id)
}
}
out, err := h.Handle(ctx, req, types.GetSpanDetailsInput{TraceID: tid, SpanIDs: filtered}) Defensive patterns
Strategy: validation
Validate before calling
func isZeroSpanID(id string) bool {
b, err := hex.DecodeString(id)
return err != nil || !bytes.Contains(b, []byte{1}) // all zeros or undecodable
}
ids := slices.DeleteFunc(rawIDs, isZeroSpanID) Try / catch
out, err := handler.Handle(ctx, req, input)
if err != nil && strings.Contains(err.Error(), "span ID must not be all zero") {
return fmt.Errorf("input contained an unset/zero span ID: %v", input.SpanIDs)
} Prevention
- Filter zero-value span IDs produced by unset protobuf fields
- Never stringify a default-initialized pcommon.SpanID as a real ID
- Investigate producers that emit zero SpanIDs in exported traces
When it happens
Trigger: Passing span_ids entries of "0000000000000000" (or all-zero after hex decoding) to get_span_details, so parseSpanID returns this error during buildQuery.
Common situations: Placeholder/nil span IDs from unmarshaled protobuf or zero-valued structs; a default-initialized SpanID stringified and fed back in; copy-paste of an all-zero sentinel from logs.
Related errors
- invalid span_id %q: %w
- trace_id is required
- start_time must be before end_time
- trace_id is required
- span_ids is required and must not be empty
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/06fe750ce0e964dd.
Report an issue: GitHub.