{"record":{"id":"f5034fa7aafd94d6","repo":"openzipkin/zipkin","slug":"not-a-valid-json-object-start-token-s","errorCode":null,"errorMessage":"Not a valid JSON object, start token: %s","messagePattern":"Not a valid JSON object, start token: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/JsonSerializers.java","lineNumber":44,"sourceCode":"  public static final JsonFactory JSON_FACTORY = new JsonFactory();\n\n  public static JsonGenerator jsonGenerator(OutputStream stream) {\n    try {\n      return JSON_FACTORY.createGenerator(stream);\n    } catch (IOException e) {\n      throw new AssertionError(\"Could not create JSON generator for a memory stream.\", e);\n    }\n  }\n\n  public interface ObjectParser<T> {\n    T parse(JsonParser jsonParser) throws IOException;\n  }\n\n  public static final ObjectParser<Span> SPAN_PARSER = JsonSerializers::parseSpan;\n\n  static Span parseSpan(JsonParser parser) throws IOException {\n    if (!parser.isExpectedStartObjectToken()) {\n      throw new IllegalArgumentException(\"Not a valid JSON object, start token: \" +\n        parser.currentToken());\n    }\n\n    Span.Builder result = Span.newBuilder();\n\n    JsonToken value;\n    while ((value = parser.nextValue()) != JsonToken.END_OBJECT) {\n      if (value == null) {\n        throw new IOException(\"End of input while parsing object.\");\n      }\n      if (value == JsonToken.VALUE_NULL) {\n        continue;\n      }\n      switch (parser.currentName()) {\n        case \"traceId\":\n          result.traceId(parser.getText());\n          break;\n        case \"parentId\":","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/JsonSerializers.java#L26-L62","documentation":"JsonSerializers.parseSpan requires the parser to start at a JSON object ({...}) before reading span fields; anything else (array, string, null token from empty input) fails immediately with IllegalArgumentException naming the offending start token. This parser decodes span documents returned from Elasticsearch, so the error means the storage returned a span-shaped position that is not a JSON object.","triggerScenarios":"Search results whose hits or source values are not objects: a malformed index containing non-object documents, a converter feeding the parser at the wrong depth, or manually crafted/consumed JSON tests that pass arrays where span objects are expected.","commonSituations":"Direct use of JsonSerializers.SPAN_PARSER in tooling/tests; corrupted index data; response-shape mismatch after cluster upgrade; feeding concatenated JSON streams.","solutions":["Inspect the JSON you feed/expect: each span must be a single object starting with '{'.","If data comes from an index, reindex or delete the malformed documents (query by _source shape to find them).","In tests/tools, wrap the parser on the correct node (the object inside hits[]._source), not the outer response.","Align zipkin versions so converters and parsers agree on response structure."],"exampleFix":"// before\nJsonParser p = factory.createParser(\"[{\\\"traceId\\\":\\\"...\\\"}]\"); // array\nSPAN_PARSER.parse(p); // Not a valid JSON object, start token: START_ARRAY\n\n// after\nJsonParser p = factory.createParser(\"{\\\"traceId\\\":\\\"...\\\",\\\"id\\\":\\\"...\\\"}\");\nSpan span = SPAN_PARSER.parse(p);","handlingStrategy":"type-guard","validationCode":"// validate shape before parsing if input provenance is unknown\nvar node = objectMapper.readTree(spanJson);\nif (!node.isObject()) {\n  throw new IOException(\"Span payload must be a JSON object, was: \" + node.getNodeType());\n}","typeGuard":"boolean isSpanObjectShape(com.fasterxml.jackson.databind.JsonNode n) {\n  return n.isObject() && n.has(\"traceId\") && n.has(\"id\");\n}","tryCatchPattern":"try {\n  Span span = JsonSerializers.SPAN_PARSER.parse(parser);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Not a valid JSON object\")) {\n    // skip/reject the malformed record, log the raw payload\n  }\n}","preventionTips":["Always anchor the parser on the span object node (hits[]._source), not the outer response.","Validate externally sourced span JSON is an object with traceId/id before parsing.","Write spans into ES only through Zipkin's own sender/collector so shapes are guaranteed."],"tags":["elasticsearch","json-parsing","span","deserialization"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}