jaegertracing/jaeger · error
failed to decode parent span ID: %w
Error message
failed to decode parent span ID: %w
What it means
convertSpan wraps failures from decodeSpanID for the ParentSpanID column with this message. Because parent IDs are optional, this only runs when ParentSpanID is non-empty; a non-empty value that is not valid 8-byte hex triggers the error.
Source
Thrown at internal/storage/v2/clickhouse/tracestore/dbmodel/from.go:115
}
func convertSpan(sr *SpanRow) (ptrace.Span, error) {
span := ptrace.NewSpan()
span.SetStartTimestamp(pcommon.NewTimestampFromTime(sr.StartTime))
traceId, err := decodeTraceID(sr.TraceID)
if err != nil {
return span, fmt.Errorf("failed to decode trace ID: %w", err)
}
span.SetTraceID(traceId)
spanId, err := decodeSpanID(sr.ID)
if err != nil {
return span, fmt.Errorf("failed to decode span ID: %w", err)
}
span.SetSpanID(spanId)
if sr.ParentSpanID != "" {
parentSpanId, err := decodeSpanID(sr.ParentSpanID)
if err != nil {
return span, fmt.Errorf("failed to decode parent span ID: %w", err)
}
span.SetParentSpanID(parentSpanId)
}
span.TraceState().FromRaw(sr.TraceState)
span.SetName(sr.Name)
span.SetKind(jptrace.StringToSpanKind(sr.Kind))
span.SetEndTimestamp(pcommon.NewTimestampFromTime(sr.StartTime.Add(time.Duration(sr.Duration))))
span.Status().SetCode(jptrace.StringToStatusCode(sr.StatusCode))
span.Status().SetMessage(sr.StatusMessage)
putAttributes(
span.Attributes(),
&sr.Attributes,
span,
)
for i, e := range sr.EventNames {
event := span.Events().AppendEmpty()View on GitHub (pinned to 806f444784)
Solutions
- Ensure root spans store an empty ParentSpanID, not zeros or placeholders
- Normalize parent IDs to exactly 16 hex chars at ingestion
- Fix or clear malformed parent_span_id values in ClickHouse
- Sanitize legacy data during migration
Example fix
// before: root span with parent "00000000" sr.ParentSpanID = "00000000" // after sr.ParentSpanID = "" // root spans must leave parent ID empty
Defensive patterns
Strategy: validation
Validate before calling
if sr.ParentSpanID != "" {
if _, ok := isSpanID(sr.ParentSpanID); !ok {
return fmt.Errorf("parent span ID %q is malformed; use empty string for root spans", sr.ParentSpanID)
}
} Type guard
func hasValidParentSpanID(sr *SpanRow) bool {
if sr.ParentSpanID == "" { return true }
_, ok := isSpanID(sr.ParentSpanID)
return ok
} Try / catch
span, err := FromRow(sr)
if err != nil && strings.Contains(err.Error(), "failed to decode parent span ID") {
log.Warn("bad parent span ID, treating as root", "parent", sr.ParentSpanID)
// proceed without parent
} Prevention
- Store empty string (not zeros) for root spans' parent IDs
- Normalize parent IDs during data migrations
- Reject placeholder parent values at ingestion
When it happens
Trigger: FromRow encounters a SpanRow with a non-empty ParentSpanID that is invalid hex or not exactly 8 bytes when decoded, e.g. root spans mistakenly given a placeholder parent like "0000" or a 16-byte parent ID.
Common situations: Root spans written with sentinel parent values instead of empty string; legacy data with 8-byte trace IDs used as parent IDs; ETL tools writing padded parent IDs.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- invalid length %d of decoded trace ID %q, expected %d bytes
- invalid length %d of decoded span ID %q, expected %d bytes
- ttl must be a non-negative duration
- ttl must be a whole number of seconds
- default_search_depth must be a positive number
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/d107ab935ccaa85a.
Report an issue: GitHub.