openzipkin/zipkin · error · IllegalArgumentException
Incomplete annotation at {}
Error message
Incomplete annotation at {} What it means
While reading a V1 (legacy) JSON span, each annotation object must contain both 'timestamp' and 'value'. V1JsonSpanReader throws 'Incomplete annotation at <jsonPath>' after finishing the annotation object when either is missing — the JSON parsed fine but the model contract was violated.
Source
Thrown at zipkin/src/main/java/zipkin2/internal/V1JsonSpanReader.java:107
String nextName;
reader.beginObject();
Long timestamp = null;
String value = null;
Endpoint endpoint = null;
while (reader.hasNext()) {
nextName = reader.nextName();
if (nextName.equals("timestamp")) {
timestamp = reader.nextLong();
} else if (nextName.equals("value")) {
value = reader.nextString();
} else if (nextName.equals("endpoint") && !reader.peekNull()) {
endpoint = ENDPOINT_READER.fromJson(reader);
} else {
reader.skipValue();
}
}
if (timestamp == null || value == null) {
throw new IllegalArgumentException("Incomplete annotation at " + reader.getPath());
}
reader.endObject();
builder.addAnnotation(timestamp, value, endpoint);
}
@Override public String toString() {
return "Span";
}
void readBinaryAnnotation(JsonReader reader) throws IOException {
String key = null;
Endpoint endpoint = null;
Boolean booleanValue = null;
String stringValue = null;
reader.beginObject();
while (reader.hasNext()) {
String nextName = reader.nextName();View on GitHub (pinned to 878ce2a1fa)
Solutions
- Locate the annotation via the reported JSON path and add the missing member (timestamp in microseconds, value as string).
- Prefer V2 JSON (SpanBytesEncoder.JSON_V2) for new integrations; V1 is compatibility-only.
- If exporting from code, always construct Annotation.create(timestamp, value) so both fields are present.
- Sanitize legacy payloads before ingest: filter annotations lacking either key.
Example fix
// before
{"annotations":[{"value":"sr"}]}
// after
{"annotations":[{"timestamp":1541036190000000,"value":"sr"}]} Defensive patterns
Strategy: validation
Validate before calling
// sanitize V1 json annotations before decode
JsonNode ann = ...; if (ann.has("timestamp") && ann.has("value")) keep(ann); else skip(ann); Type guard
boolean isCompleteV1Annotation(JsonNode n) { return n.hasNonNull("timestamp") && n.hasNonNull("value"); } Prevention
- Always create annotations via Annotation.create(timestamp, value).
- Move producers to V2 JSON to reduce legacy edge cases.
When it happens
Trigger: Decoding with SpanBytesDecoder.JSON_V1 a span whose annotations[] entry lacks 'timestamp' or 'value' (e.g. {"value":"sr"} or {"timestamp":...}).
Common situations: Hand-written V1 JSON fixtures; legacy exporters (finagle, brave pre-3.x formats) that omit timestamps on some annotations; ETL pipelines stripping null fields and dropping a zero timestamp.
Related errors
- No key at {}
- Incomplete annotation at {}
- Expected json or thrift object, not list encoding
- %s reading %s from json
- No value at {}
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/ad88eff8a89627ed.
Report an issue: GitHub.