jaegertracing/jaeger · error
invalid length %d of decoded trace ID %q, expected %d bytes
Error message
invalid length %d of decoded trace ID %q, expected %d bytes
What it means
decodeTraceID converts a hex string from ClickHouse into a 16-byte pcommon.TraceID. This error is thrown when the hex string decodes successfully but does not yield exactly 16 bytes, which is the fixed size of an OpenTelemetry trace ID. The library validates this to guarantee a well-formed pcommon.TraceID can be constructed.
Source
Thrown at internal/storage/v2/clickhouse/tracestore/dbmodel/from.go:78
putAttributes(
scope.Attributes(),
&sr.ScopeAttributes,
spanForWarnings,
)
return scope
}
// decodeTraceID decodes a hex string into a pcommon.TraceID, validating that
// it contains exactly 16 bytes so the conversion cannot panic on corrupted rows.
func decodeTraceID(s string) (pcommon.TraceID, error) {
var id pcommon.TraceID
b, err := hex.DecodeString(s)
if err != nil {
return id, err
}
if len(b) != len(id) {
return id, fmt.Errorf("invalid length %d of decoded trace ID %q, expected %d bytes", len(b), s, len(id))
}
copy(id[:], b)
return id, nil
}
// decodeSpanID decodes a hex string into a pcommon.SpanID, validating that
// it contains exactly 8 bytes so the conversion cannot panic on corrupted rows.
func decodeSpanID(s string) (pcommon.SpanID, error) {
var id pcommon.SpanID
b, err := hex.DecodeString(s)
if err != nil {
return id, err
}
if len(b) != len(id) {
return id, fmt.Errorf("invalid length %d of decoded span ID %q, expected %d bytes", len(b), s, len(id))
}
copy(id[:], b)
return id, nilView on GitHub (pinned to 806f444784)
Solutions
- Verify the trace IDs stored in ClickHouse are 32 hex characters (16 bytes) once decoded
- Check the ingestion pipeline — the writer must zero-pad or preserve full 16-byte trace IDs
- Inspect the offending row(s) and repair or drop malformed trace_id values
- If legacy 8-byte IDs exist, migrate them by left-padding with zeros to 16 bytes before storing
Example fix
// before: legacy 8-byte trace id string "abcdef0123456789" (8 bytes) fails validation
// after: pad to 16 bytes before writing/decoding
padded := strings.Repeat("0", 32-len(s)) + s
id, err := decodeTraceID(padded) Defensive patterns
Strategy: validation
Validate before calling
func validTraceIDHex(s string) bool {
b, err := hex.DecodeString(s)
return err == nil && len(b) == 16
}
// before querying: if !validTraceIDHex(row.TraceID) { skip/repair } Type guard
func isTraceID(s string) (pcommon.TraceID, bool) {
var id pcommon.TraceID
b, err := hex.DecodeString(s)
if err != nil || len(b) != len(id) { return id, false }
copy(id[:], b)
return id, true
} Try / catch
span, err := FromRow(row)
if err != nil {
if strings.Contains(err.Error(), "invalid length") {
log.Warn("skipping row with malformed trace ID", "err", err)
continue
}
return err
} Prevention
- Always write full 16-byte (32 hex char) trace IDs to ClickHouse
- Zero-pad legacy 8-byte IDs during migration
- Validate ID formats at ingestion, not at read time
When it happens
Trigger: Calling FromRow/convertSpan with a SpanRow whose TraceID column holds a hex string that decodes to fewer or more than 16 bytes, e.g. an empty string, a 32-hex-digit ID from a 16-byte-encoded source that was truncated, or a legacy 8-byte trace ID (16 hex chars).
Common situations: Migrating data from older Jaeger storage where trace IDs were 8 bytes; manual data inserts with malformed IDs; ClickHouse columns typed as String allowing arbitrary-length values.
Related errors
- failed to decode trace ID: %w
- TraceID is not a 128bit integer
- invalid length %d of decoded span ID %q, expected %d bytes
- failed to decode parent span ID: %w
- internal data consistency issue
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/9c6e480ccda76710.
Report an issue: GitHub.