openzipkin/zipkin · error · IllegalArgumentException

Incomplete annotation at {}

Error message

Incomplete annotation at {}

What it means

After parsing an annotation object, if timestamp == 0 or value == null it is considered incomplete and IllegalArgumentException('Incomplete annotation at <token>') is thrown. A timestamp of exactly 0 is treated as missing because real Zipkin timestamps are epoch-microseconds and never 0; a null value means the 'value' field was absent.

Source

Thrown at zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/JsonSerializers.java:183

    long timestamp = 0;
    String value = null;

    while (parser.nextValue() != JsonToken.END_OBJECT) {
      switch (parser.currentName()) {
        case "timestamp":
          timestamp = parser.getLongValue();
          break;
        case "value":
          value = parser.getValueAsString();
          break;
        default:
          // Skip
      }
    }

    if (timestamp == 0 || value == null) {
      throw new IllegalArgumentException("Incomplete annotation at " + parser.currentToken());
    }
    return Annotation.create(timestamp, value);
  }

  public static final ObjectParser<DependencyLink> DEPENDENCY_LINK_PARSER = parser -> {
    if (!parser.isExpectedStartObjectToken()) {
      throw new IllegalArgumentException("Expected start of dependency link object but was "
        + parser.currentToken());
    }

    DependencyLink.Builder result = DependencyLink.newBuilder();
    JsonToken value;
    while ((value = parser.nextValue()) != JsonToken.END_OBJECT) {
      if (value == null) {
        throw new IOException("End of input while parsing object.");
      }
      switch (parser.currentName()) {
        case "parent":

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Ensure every annotation has both fields: {"timestamp":<epoch-micros>,"value":"..."} with timestamp > 0.
  2. Fix the producer to skip annotations lacking a timestamp instead of writing incomplete ones.
  3. Clean up or reindex malformed documents already stored.
  4. In Java code, Annotation.create(timestamp, value) requires the same pair — apply the same rule upstream.

Example fix

// before
{"annotations":[{"value":"sr"}]}
// -> IllegalArgumentException: Incomplete annotation at null

// after
{"annotations":[{"timestamp":1470150004000000,"value":"sr"}]}
Defensive patterns

Strategy: validation

Validate before calling

for (JsonNode a : span.path("annotations")) {
  if (!a.isObject() || a.path("timestamp").asLong(0) == 0 || !a.has("value")) {
    throw new IOException("annotation missing timestamp(>0) or value: " + a);
  }
}

Type guard

boolean annotationComplete(JsonNode a) {
  return a.isObject() && a.path("timestamp").isNumber() && a.path("timestamp").asLong() > 0
      && a.has("value") && !a.get("value").isNull();
}

Try / catch

try { Span s = SPAN_PARSER.parse(p); }
catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Incomplete annotation")) {
    // drop/reject the document and fix the producer to always set timestamp and value
  }
}

Prevention

When it happens

Trigger: An annotation object missing 'timestamp' or 'value', or with timestamp: 0, e.g. {"value":"sr"} or {"timestamp":0,"value":"sr"}, inside the annotations array of a span being parsed.

Common situations: Fixtures written from memory that omit timestamps; converters dropping zero/absent timestamps; edge data where timestamp legitimately underflows to 0.

Related errors


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