{"record":{"id":"ad88eff8a89627ed","repo":"openzipkin/zipkin","slug":"incomplete-annotation-at-ad88ef","errorCode":null,"errorMessage":"Incomplete annotation at {}","messagePattern":"Incomplete annotation at (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin/src/main/java/zipkin2/internal/V1JsonSpanReader.java","lineNumber":107,"sourceCode":"    String nextName;\n    reader.beginObject();\n    Long timestamp = null;\n    String value = null;\n    Endpoint endpoint = null;\n    while (reader.hasNext()) {\n      nextName = reader.nextName();\n      if (nextName.equals(\"timestamp\")) {\n        timestamp = reader.nextLong();\n      } else if (nextName.equals(\"value\")) {\n        value = reader.nextString();\n      } else if (nextName.equals(\"endpoint\") && !reader.peekNull()) {\n        endpoint = ENDPOINT_READER.fromJson(reader);\n      } else {\n        reader.skipValue();\n      }\n    }\n    if (timestamp == null || value == null) {\n      throw new IllegalArgumentException(\"Incomplete annotation at \" + reader.getPath());\n    }\n    reader.endObject();\n    builder.addAnnotation(timestamp, value, endpoint);\n  }\n\n  @Override public String toString() {\n    return \"Span\";\n  }\n\n  void readBinaryAnnotation(JsonReader reader) throws IOException {\n    String key = null;\n    Endpoint endpoint = null;\n    Boolean booleanValue = null;\n    String stringValue = null;\n\n    reader.beginObject();\n    while (reader.hasNext()) {\n      String nextName = reader.nextName();","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin/src/main/java/zipkin2/internal/V1JsonSpanReader.java#L89-L125","documentation":"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.","triggerScenarios":"Decoding with SpanBytesDecoder.JSON_V1 a span whose annotations[] entry lacks 'timestamp' or 'value' (e.g. {\"value\":\"sr\"} or {\"timestamp\":...}).","commonSituations":"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.","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."],"exampleFix":"// before\n{\"annotations\":[{\"value\":\"sr\"}]}\n\n// after\n{\"annotations\":[{\"timestamp\":1541036190000000,\"value\":\"sr\"}]}","handlingStrategy":"validation","validationCode":"// sanitize V1 json annotations before decode\nJsonNode ann = ...; if (ann.has(\"timestamp\") && ann.has(\"value\")) keep(ann); else skip(ann);","typeGuard":"boolean isCompleteV1Annotation(JsonNode n) { return n.hasNonNull(\"timestamp\") && n.hasNonNull(\"value\"); }","tryCatchPattern":null,"preventionTips":["Always create annotations via Annotation.create(timestamp, value).","Move producers to V2 JSON to reduce legacy edge cases."],"tags":["zipkin","json","v1","annotation"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}