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
- Treat an all-zero incoming ID as 'no ID' and generate a fresh one instead of forwarding it.
- Fix the conversion step: never stringify a 0L long into an ID — handle 0L at the long level (see error 122).
- 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
- Handle 0L at the long level before stringifying (see 'empty id').
- Reject all-zero IDs at ingestion boundaries (collector/reporter).
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.