{"record":{"id":"2ba8a2d83a3fedd0","repo":"elastic/elasticsearch","slug":"expected-data-to-start-with-an-object","errorCode":null,"errorMessage":"expected data to start with an object","messagePattern":"expected data to start with an object","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"client/sniffer/src/main/java/org/elasticsearch/client/sniff/ElasticsearchNodesSniffer.java","lineNumber":114,"sourceCode":"        this.request = new Request(\"GET\", \"/_nodes/http\");\n        request.addParameter(\"timeout\", sniffRequestTimeoutMillis + \"ms\");\n        this.scheme = Objects.requireNonNull(scheme, \"scheme cannot be null\");\n    }\n\n    /**\n     * Calls the elasticsearch nodes info api, parses the response and returns all the found http hosts\n     */\n    @Override\n    public List<Node> sniff() throws IOException {\n        Response response = restClient.performRequest(request);\n        return readHosts(response.getEntity(), scheme, jsonFactory);\n    }\n\n    static List<Node> readHosts(HttpEntity entity, Scheme scheme, JsonFactory jsonFactory) throws IOException {\n        try (InputStream inputStream = entity.getContent()) {\n            JsonParser parser = jsonFactory.createParser(inputStream);\n            if (parser.nextToken() != JsonToken.START_OBJECT) {\n                throw new IOException(\"expected data to start with an object\");\n            }\n            List<Node> nodes = new ArrayList<>();\n            while (parser.nextToken() != JsonToken.END_OBJECT) {\n                if (parser.getCurrentToken() == JsonToken.START_OBJECT) {\n                    if (\"nodes\".equals(parser.getCurrentName())) {\n                        while (parser.nextToken() != JsonToken.END_OBJECT) {\n                            JsonToken token = parser.nextToken();\n                            assert token == JsonToken.START_OBJECT;\n                            String nodeId = parser.getCurrentName();\n                            Node node = readNode(nodeId, parser, scheme);\n                            if (node != null) {\n                                nodes.add(node);\n                            }\n                        }\n                    } else {\n                        parser.skipChildren();\n                    }\n                }","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/client/sniffer/src/main/java/org/elasticsearch/client/sniff/ElasticsearchNodesSniffer.java#L96-L132","documentation":"Thrown by readHosts when parsing the /_nodes/http response: the first JSON token must be START_OBJECT (the outer nodes-info envelope). If the parser sees an array, a string, or anything else, the response is not a valid nodes-info document and sniffer cannot extract hosts.","triggerScenarios":"The endpoint returned a non-JSON-object body: an array of errors, a plain string, HTML error page, or a proxy interstitial. Reached via Sniffer.sniff() -> ElasticsearchNodesSniffer.sniff().","commonSituations":"Sniffing against a URL that is fronted by a load balancer/proxy returning a different shape; wrong scheme/port hitting a non-ES service; ES returned an error array; authentication challenge returning an HTML page.","solutions":["Verify the sniff endpoint (/_nodes/http) returns the standard ES nodes-info object: curl it directly.","Ensure the RestClient is pointed at the real ES HTTP layer, not a proxy/HTML gateway.","If behind a proxy, configure the proxy to pass through to ES unchanged, or sniff a fixed host list instead."],"exampleFix":"// before\nRestClient client = RestClient.builder(new HttpHost(\"proxy\", 80, \"http\")).build();\nSniffer sniffer = Sniffer.builder(client).build();\n// after\nRestClient client = RestClient.builder(new HttpHost(\"es-internal\", 9200, \"http\")).build();\nSniffer sniffer = Sniffer.builder(client).build();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { sniffer.sniff(); }\ncatch (IOException e) {\n    if (e.getMessage().equals(\"expected data to start with an object\")) {\n        // endpoint returned a non-ES body: disable sniffing or fix the proxy\n    } else throw e;\n}","preventionTips":["curl /_nodes/http directly to confirm the response shape before enabling sniffing.","Make sure the client talks to ES, not an HTML/JSON-error gateway."],"tags":["sniffer","parsing","json","network","configuration"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}