openzipkin/zipkin · error · IllegalArgumentException

id is empty

Error message

id is empty

What it means

Span.Builder.id(String id) throws IllegalArgumentException('id is empty') when the argument is non-null but has length 0. An empty string is not a valid lower-hex span ID (valid ones are 1-16 hex chars, padded to 16 internally). The check runs before the length>16 and hex checks.

Source

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

      }
      return this;
    }

    /**
     * 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;

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Validate the extracted ID is non-empty before calling the builder; treat blank as missing.
  2. Parse the b3 single header with a strict parser instead of String.split so malformed headers fail loudly upstream.
  3. Fall back to generating a new span ID when the incoming value is blank.

Example fix

// before
b.id(b3Header.split("-")[1]);

// after
String[] parts = b3Header.split("-");
String sid = parts.length > 1 && !parts[1].isEmpty() ? parts[1] : null;
b.id(sid != null ? sid : HexCodec.toLowerHex(ThreadLocalRandom.current().nextLong()));
Defensive patterns

Strategy: validation

Validate before calling

boolean validSpanId(String s) {
  return s != null && !s.isEmpty() && s.matches("[0-9a-f]{1,16}")
      && s.chars().anyMatch(c -> c != '0');
}
// if (validSpanId(sid)) b.id(sid); else b.id(newIdHex());

Prevention

When it happens

Trigger: Calling .id("") directly, or passing a header value, substring, or trimmed string that ended up as the empty string.

Common situations: Mapping x-b3-spanid or the b3 single header into the builder without normalizing blank values; buggy header parsing (e.g. split("-")[1] on a malformed b3 header) that yields an empty segment.

Related errors


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