openzipkin/zipkin · error · IllegalArgumentException

traceId == 0

Error message

traceId == 0

What it means

Thrown by the V1Span constructor (zipkin2.v1) when the builder's 64-bit traceId is 0. A span's traceId identifies the trace it belongs to; 0 is reserved to mean 'unset' in Zipkin, so constructing a V1 span without a real trace id is treated as a programming error.

Source

Thrown at zipkin/src/main/java/zipkin2/v1/V1Span.java:93

   */
  public List<V1BinaryAnnotation> binaryAnnotations() {
    return binaryAnnotations;
  }

  /** Same as {@link Span#debug()} */
  public Boolean debug() {
    return debug;
  }

  final long traceIdHigh, traceId, id;
  final String name;
  final long parentId, timestamp, duration;
  final List<V1Annotation> annotations;
  final List<V1BinaryAnnotation> binaryAnnotations;
  final Boolean debug;

  V1Span(Builder builder) {
    if (builder.traceId == 0L) throw new IllegalArgumentException("traceId == 0");
    if (builder.id == 0L) throw new IllegalArgumentException("id == 0");
    this.traceId = builder.traceId;
    this.traceIdHigh = builder.traceIdHigh;
    this.name = builder.name;
    this.id = builder.id;
    this.parentId = builder.parentId;
    this.timestamp = builder.timestamp;
    this.duration = builder.duration;
    this.annotations = sortedList(builder.annotations);
    this.binaryAnnotations = sortedList(builder.binaryAnnotations);
    this.debug = builder.debug;
  }

  public static Builder newBuilder() {
    return new Builder();
  }

  public static final class Builder {

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Always supply a non-zero 64-bit trace id when constructing the V1Span builder
  2. If the id arrives as hex, validate parse output: reject empty strings and check the parsed long is != 0 before building
  3. Generate ids with a proper id generator (e.g. zipkin's or Brave's) instead of constants like 0L in tests

Example fix

// before
V1Span span = new V1Span.Builder(0L, 1L).name("get").build();

// after
V1Span span = new V1Span.Builder(0LL + traceIdFromContext, 1L).name("get").build();
Defensive patterns

Strategy: validation

Validate before calling

// validate before constructing the V1 span
if (traceId == 0L) {
    throw new IllegalArgumentException(
        "traceId is required: got 0 (unset or failed hex parse) for id=" + id);
}
V1Span span = new V1Span.Builder(traceId, id).name(name).build();

Try / catch

try {
    return new V1Span.Builder(traceId, id).name(name).build();
} catch (IllegalArgumentException e) {
    // drop or reject the malformed span record; never retry with the same ids
    LOG.warn("Discarding span with invalid ids: traceId={}, id={}", traceId, id);
    return null; // or route to a dead-letter path
}

Prevention

When it happens

Trigger: Building a V1Span with new V1Span.Builder(0L, id); parsing v1 JSON where the 128-bit trace id string is malformed so the low 64 bits parse as 0; converting instrumentation data whose traceId field was never populated or was truncated to 0 by a hex-parsing bug.

Common situations: Custom instrumentation or a bridging layer (e.g. translating from another tracing system) that leaves traceId unset; lower-case/upper-case hex parsing that fails silently and returns 0; tests that build V1 spans with placeholder zero ids.

Related errors


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