{"record":{"id":"41f970565246e5e3","repo":"openzipkin/zipkin","slug":"expected-start-object-was-s","errorCode":null,"errorMessage":"Expected start object, was %s","messagePattern":"Expected start object, was (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/JsonReaders.java","lineNumber":105,"sourceCode":"        break;\n      case START_OBJECT:\n        visitObject(parser, name, result);\n        break;\n      default:\n        // Skip current value.\n    }\n  }\n\n  static boolean checkStartObject(JsonParser parser, boolean shouldThrow) throws IOException {\n    try {\n      JsonToken currentToken = parser.currentToken();\n      // The parser may not be at a token, yet. If that's the case advance.\n      if (currentToken == null) currentToken = parser.nextToken();\n\n      // If we are still not at the expected token, we could be an another or an empty body.\n      if (currentToken == JsonToken.START_OBJECT) return true;\n      if (shouldThrow) {\n        throw new IllegalArgumentException(\"Expected start object, was \" + currentToken);\n      }\n      return false;\n    } catch (Throwable e) { // likely not json\n      if (shouldThrow) throw e;\n      return false;\n    }\n  }\n\n  JsonReaders() {\n  }\n}\n","sourceCodeStart":87,"sourceCodeEnd":117,"githubUrl":"https://github.com/openzipkin/zipkin/blob/878ce2a1fad54ca941d17fdcf2e1d924b148eb1f/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/JsonReaders.java#L87-L117","documentation":"JsonReaders.checkStartObject(parser, shouldThrow) verifies the parser is positioned on (or can advance to) a START_OBJECT token. With shouldThrow=true, any other token — or a non-JSON body, which makes the parser throw — is surfaced as IllegalArgumentException('Expected start object, was <token>'). It is used when entering objects of search responses, so it fires when the response is not the JSON object shape the client expects.","triggerScenarios":"An Elasticsearch search/cluster call returns a JSON array, a scalar, an error envelope at the wrong depth, or a non-JSON body (HTML error page, empty-but-status-200) at a point where Zipkin's internal readers call checkStartObject with shouldThrow=true.","commonSituations":"A proxy or captive portal returning HTML; ES returning an error body with HTTP 200; version-skew where response shapes changed; hitting a non-ES port.","solutions":["Capture the raw HTTP response the storage receives (curl the same URL Zipkin uses) and compare it with a known-good Elasticsearch/OpenSearch response.","Remove the intermediary rewriting responses, or point ES_HOSTS directly at real ES nodes.","Match the zipkin-server version to your cluster version so expected response shapes agree.","Check ES credentials/permissions if the body is an auth error delivered with 200."],"exampleFix":"# before: ES_HOSTS=http://es:9300  (transport port, returns non-JSON)\n# -> IllegalArgumentException: Expected start object, was ...\n\n# after: ES_HOSTS=http://es:9200  (HTTP port returning JSON objects)","handlingStrategy":"try-catch","validationCode":"// confirm endpoints return JSON objects before wiring storage\nvar resp = http.get(esHost + \"/_cluster/health\");\nif (!resp.body().trim().startsWith(\"{\")) {\n  throw new IllegalStateException(\"Expected JSON object from ES, got: \" + resp.body().substring(0, 80));\n}","typeGuard":null,"tryCatchPattern":"try {\n  V result = call.execute();\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Expected start object\")) {\n    // response is not the JSON object shape expected: check proxy/auth/ES version skew\n  }\n  throw e;\n}","preventionTips":["Point ES_HOSTS at real ES HTTP ports (9200) verified with curl.","Keep proxies from rewriting ES responses; check for HTML error pages on auth failures.","Match zipkin-server and cluster versions to avoid response-shape drift."],"tags":["elasticsearch","json-parsing","client","proxy","configuration"],"backgroundTag":null,"analyzedSha":"878ce2a1fad54ca941d17fdcf2e1d924b148eb1f","analyzedAt":"2026-08-14T15:17:09.895Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}