openzipkin/zipkin · error · IllegalArgumentException

id is all zeros

Error message

id is all zeros

What it means

Span.Builder.id(String id) throws IllegalArgumentException('id is all zeros') when validateHexAndReturnZeroPrefix(id) returns 16, i.e. the (padded) ID is 16 zero characters. Zipkin forbids a zero span ID because it cannot serve as a unique reference for parent-child links. Note this exact check is length-independent: any all-zero input like "0" or "0000000000000000" triggers it after padding logic in the helper.

Source

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

    /**
     * Hex encodes the input as the {@link Span#id()} or throws IllegalArgumentException if the
     * input is zero.
     */
    public Builder id(long id) {
      if (id == 0L) throw new IllegalArgumentException("empty id");
      this.id = toLowerHex(id);
      return this;
    }

    /** Sets {@link Span#id()} or throws {@link IllegalArgumentException} if not lower-hex format. */
    public Builder id(String id) {
      if (id == null) throw new NullPointerException("id == null");
      int length = id.length();
      if (length == 0) throw new IllegalArgumentException("id is empty");
      if (length > 16) throw new IllegalArgumentException("id.length > 16");
      if (validateHexAndReturnZeroPrefix(id) == 16) {
        throw new IllegalArgumentException("id is all zeros");
      }
      this.id = length < 16 ? padLeft(id, 16) : id;
      return this;
    }

    /** Sets {@link Span#kind} */
    public Builder kind(@Nullable Kind kind) {
      this.kind = kind;
      return this;
    }

    /** Sets {@link Span#name} */
    public Builder name(@Nullable String name) {
      this.name = name == null || name.isEmpty() ? null : name.toLowerCase(Locale.ROOT);
      return this;
    }

    /** Sets {@link Span#timestampAsLong()} */

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Treat an all-zero incoming ID as 'no ID' and generate a fresh one instead of forwarding it.
  2. Fix the conversion step: never stringify a 0L long into an ID — handle 0L at the long level (see error 122).
  3. Sanitize at the edge: reject/replace zero IDs when accepting spans over the wire or from headers.

Example fix

// before
b.id(toLowerHex(parsedSpanId)); // parsedSpanId == 0 -> "0000000000000000"

// after
b.id(parsedSpanId != 0L ? toLowerHex(parsedSpanId)
    : toLowerHex(ThreadLocalRandom.current().nextLong()));
Defensive patterns

Strategy: validation

Validate before calling

boolean allZeros(String s) {
  return s.chars().allMatch(c -> c == '0');
}
// if (sid != null && allZeros(sid)) sid = newSpanIdHex();

Prevention

When it happens

Trigger: Calling .id("0"), .id("0000000000000000"), or a hex string produced from the long 0L via toLowerHex.

Common situations: Converting an absent/failed-to-parse span ID into the literal string of zeros before passing it in; copied test fixtures with zero IDs; upstream services (or W3C traceparent implementations) that emit all-zero IDs to mean 'invalid', forwarded verbatim.

Related errors


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