openzipkin/zipkin · error · IllegalArgumentException

traceId is all zeros

Error message

traceId is all zeros

What it means

Span.normalizeTraceId(String) throws IllegalArgumentException('traceId is all zeros') when every character is '0' (validateHexAndReturnZeroPrefix returns the full length). Zipkin requires trace IDs to be non-zero; a zero trace ID cannot identify a trace. The check runs after length/oversize checks and before padding.

Source

Thrown at zipkin/src/main/java/zipkin2/Span.java:628

    }
  }

  @Override public String toString() {
    return new String(SpanBytesEncoder.JSON_V2.encode(this), UTF_8);
  }

  /**
   * Returns a valid lower-hex trace ID, padded left as needed to 16 or 32 characters.
   *
   * @throws IllegalArgumentException if oversized or not lower-hex
   */
  public static String normalizeTraceId(String traceId) {
    if (traceId == null) throw new NullPointerException("traceId == null");
    int length = traceId.length();
    if (length == 0) throw new IllegalArgumentException("traceId is empty");
    if (length > 32) throw new IllegalArgumentException("traceId.length > 32");
    int zeros = validateHexAndReturnZeroPrefix(traceId);
    if (zeros == length) throw new IllegalArgumentException("traceId is all zeros");
    if (length == 32 || length == 16) {
      if (length == 32 && zeros >= 16) return traceId.substring(16);
      return traceId;
    } else if (length < 16) {
      return padLeft(traceId, 16);
    } else {
      return padLeft(traceId, 32);
    }
  }

  static final String THIRTY_TWO_ZEROS;
  static {
    char[] zeros = new char[32];
    Arrays.fill(zeros, '0');
    THIRTY_TWO_ZEROS = new String(zeros);
  }

  static String padLeft(String id, int desiredLength) {

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Treat an all-zero trace ID as 'no trace' and start a new trace (generate a fresh ID).
  2. Reject or fix the upstream producer that emits zero trace IDs.
  3. Guard with a regex/long-parse check before normalizing: any parsed value of zero means absent.

Example fix

// before
b.traceId(incomingTraceId); // "0000000000000000"

// after
if (incomingTraceId == null || incomingTraceId.chars().allMatch(c -> c == '0')) {
  incomingTraceId = newTraceId();
}
b.traceId(incomingTraceId);
Defensive patterns

Strategy: validation

Validate before calling

boolean usable(String t) {
  return t != null && !t.isEmpty() && !t.chars().allMatch(c -> c == '0');
}
// traceId = usable(raw) ? raw : newTraceId();

Prevention

When it happens

Trigger: Calling normalizeTraceId("0"), normalizeTraceId("0000000000000000"), or a 32-char all-zero ID; passing a trace ID stringified from two 0L longs.

Common situations: Receiving all-zero trace IDs from misbehaving clients or from tracestate/traceparent implementations that use zeros as 'invalid'; defaulting trace IDs to "0" in config or test data; converting an uninitialized 128-bit ID array to hex.

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/cac0f8a676a269b6. Report an issue: GitHub.