openzipkin/zipkin · error · IllegalArgumentException
empty id
Error message
empty id
What it means
Span.Builder.id(long id) hex-encodes a 64-bit span ID and throws IllegalArgumentException('empty id') when the value is 0L. A span ID of zero is reserved/invalid in the Zipkin model, exactly like an all-zero hex ID. Every span must have a non-zero ID so it can be uniquely referenced as a parent by child spans.
Source
Thrown at zipkin/src/main/java/zipkin2/Span.java:448
return this;
}
int length = parentId.length();
if (length == 0) throw new IllegalArgumentException("parentId is empty");
if (length > 16) throw new IllegalArgumentException("parentId.length > 16");
if (validateHexAndReturnZeroPrefix(parentId) == length) {
this.parentId = null;
} else {
this.parentId = length < 16 ? padLeft(parentId, 16) : parentId;
}
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} */View on GitHub (pinned to 878ce2a1fa)
Solutions
- Ensure the ID is generated with a non-zero generator (e.g. ThreadLocalRandom.current().nextLong() retried on 0, or the tracer's built-in ID generator).
- If the ID genuinely may be absent, skip creating the span instead of defaulting the long to 0.
- If you hold the ID as a hex string, use .id(String) which validates the hex form directly.
Example fix
// before long spanId = context.spanId(); // may be 0 when absent b.id(spanId); // after long spanId = context.spanId(); if (spanId == 0L) spanId = ThreadLocalRandom.current().nextLong(); b.id(spanId);
Defensive patterns
Strategy: validation
Validate before calling
long nonZeroSpanId(long candidate) {
return candidate != 0L ? candidate : ThreadLocalRandom.current().nextLong();
}
// b.id(nonZeroSpanId(ctx.spanId())); Prevention
- Use the tracer's ID generator instead of raw Random.
- Never use a primitive long default of 0 as a stand-in for a missing span ID.
When it happens
Trigger: Calling .id(0L) directly, or passing a long that was never assigned because the ID source (MDC, context, random generator result assigned conditionally) was missing.
Common situations: Custom instrumentation that generates span IDs with new Random().nextLong() and forgets that nextLong() can return 0 (rare but real), or code paths that read a span ID from a context object that was not initialized for this request.
Related errors
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/dd45558aeb3ae178.
Report an issue: GitHub.