NationalSecurityAgency/ghidra · error · ElasticException

Could not find hits document

Error message

Could not find hits document

What it means

Thrown in queryNearestVector after issuing a GET vector/_search request with a lsh_compare script_score query. The Elasticsearch response JSON object does not contain a top-level "hits" key (baseHits == null). The BSim query protocol assumes every search response carries a hits document; its absence means the server returned an unexpected response shape, typically because the custom bsim_scripts plugin (lsh_compare) is missing or the script threw an internal error that did not surface as an HTTP-level failure.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java:850

		buffer.append("    \"min_score\": 0.00001, ");		// Make sure a 0.0 score is filtered
		buffer.append("    \"boost_mode\": \"replace\", ");
		buffer.append("    \"functions\": [ { ");
		buffer.append("      \"script_score\": { ");
		buffer.append("        \"script\": { ");
		buffer.append("          \"lang\": \"bsim_scripts\", ");
		buffer.append("          \"source\": \"lsh_compare\", ");
		buffer.append("          \"params\": { ");
		buffer.append("            \"indexname\": \"lsh_").append(repository).append("\", ");
		buffer.append("            \"vector\": \"");
		buffer.append(vecEncode);
		buffer.append("\",          \"simthresh\": ").append(similarityThreshold);
		buffer.append(",            \"sigthresh\": ").append(significanceThreshold);
		buffer.append(" } } } } ] } } }");
		JsonObject resp =
			connection.executeStatement(ElasticConnection.GET, "vector/_search", buffer.toString());
		JsonObject baseHits = (JsonObject) resp.get("hits");
		if (baseHits == null) {
			throw new ElasticException("Could not find hits document");
		}
		JsonObject totalRec = (JsonObject) baseHits.get("total");
		long numHits = totalRec.get("value").getAsLong();
		if (numHits == 0) {
			return 0;
		}
		JsonArray hitsArray = (JsonArray) baseHits.get("hits");
		char[] decodeBuffer = Base64VectorFactory.allocateBuffer();
		VectorCompare vecCompare = new VectorCompare();
		try {
			int returnedHits = hitsArray.size();
			for (int i = 0; i < returnedHits; ++i) {
				JsonObject mainHit = (JsonObject) hitsArray.get(i);
				VectorResult vecRes = new VectorResult();
				vecRes.vectorid = Base64Lite.decodeLongBase64(mainHit.get("_id").getAsString());
				vecRes.hitcount = -1;		// Cannot fill in at this time
				vecRes.sim = mainHit.get("_score").getAsDouble();
				JsonObject source = (JsonObject) mainHit.get("_source");

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Verify the BSim Elasticsearch plugin is installed on every node (bin/elasticsearch-plugin list should include the lsh plugin) and restart the cluster if it was just added.
  2. Confirm the vector index exists and was created via createVectorIndex by checking that initialize/generate completed successfully for this repository.
  3. Issue the same vector/_search POST manually via curl against the Elasticsearch server and inspect the raw response for the hits key or an embedded error.
  4. Ensure the Elasticsearch server version is compatible with LAYOUT_VERSION 3 as implemented by this ElasticDatabase class.
Defensive patterns

Strategy: validation

Validate before calling

// Before querying, verify the vector index and plugin are healthy
ElasticConnection conn = database.getConnection(); // if accessible
JsonObject settings = conn.executeURIOnly(ElasticConnection.GET, "vector/_settings");
if (settings == null || !settings.toString().contains("lsh_")) {
    throw new IllegalStateException("BSim lsh tokenizer plugin not configured on server");
}

Try / catch

try {
    database.query(queryNearest);
} catch (ElasticException e) {
    if (e.getMessage().contains("Could not find hits document")) {
        // Server-side plugin or index issue; not retryable without infra fix
        Msg.error(this, "Vector search failed — verify BSim plugin installation: " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling queryNearestVector (reached via QueryNearest commands or any similarity search). The lsh_compare script_score sub-query returns a JSON response whose top-level keys do not include "hits". This happens when the repository_vector index exists but the bsim_scripts plugin script is not registered, when the script errors internally and Elasticsearch wraps the error in a non-standard envelope, or when a proxy modifies the response body.

Common situations: Elasticsearch server lacks the BSim plugin (bsim_scripts / lsh_tokenizer); querying a database whose vector index was partially created; Elasticsearch major-version upgrade that changed the search response envelope; HTTP proxy or load balancer stripping fields from the response.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/2cf851f4d96800c3. Report an issue: GitHub.