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
- 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.
- Confirm the vector index exists and was created via createVectorIndex by checking that initialize/generate completed successfully for this repository.
- 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.
- 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
- Verify the BSim Elasticsearch plugin is installed on all cluster nodes before creating or querying the database.
- Run a health check query (vector/_settings) after initialize() to confirm the lsh tokenizer is present.
- Document the required Elasticsearch plugin version alongside the BSim LAYOUT_VERSION in deployment guides.
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
- Multi-search for exe records failed
- {getType()}scripts cannot be used for context [{context.name
- Unknown script name {scriptSource}
- No functions matching vectorid:
- Could not recover unique executable via id
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/2cf851f4d96800c3.
Report an issue: GitHub.