NationalSecurityAgency/ghidra · error · ElasticException
Multi-search for exe records failed
Error message
Multi-search for exe records failed
What it means
Thrown in queryExecutableRecordById when one sub-response in an Elasticsearch _msearch (multi-search) bulk request is missing its "hits" field, as detected by ElasticConnection.isNull(hits). Each sub-response in an msearch should contain a hits object; its absence means that individual search failed (e.g., the error envelope replaced the normal hits object).
Source
Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java:1131
int count = 0;
for (int i = 0; i < maxDocuments; ++i) {
String exeId = iter1.next().generateExeIdString();
buffer.append("{}\n"); // Keep default index and type
buffer.append("{ \"query\": { \"bool\": { \"filter\": { \"term\": { \"_id\": \"");
buffer.append(exeId);
buffer.append("\" }}}}}\n");
count += 1;
if (!iter1.hasNext()) {
break;
}
}
JsonObject bulkobj = connection.executeBulk(path, buffer.toString());
JsonArray responses = (JsonArray) bulkobj.get("responses");
for (int i = 0; i < count; ++i) {
JsonObject subquery = (JsonObject) responses.get(i);
JsonElement hits = subquery.get("hits");
if (ElasticConnection.isNull(hits)) {
throw new ElasticException("Multi-search for exe records failed");
}
JsonObject totalRec = (JsonObject) ((JsonObject) hits).get("total");
long total = totalRec.get("value").getAsLong();
if (total != 1) {
throw new ElasticException("Could not recover unique executable via id");
}
}
for (int i = 0; i < count; ++i) {
JsonObject subquery = (JsonObject) responses.get(i);
JsonObject hits = (JsonObject) subquery.get("hits");
JsonArray hitsArray = (JsonArray) hits.get("hits");
hits = (JsonObject) hitsArray.get(0);
ExecutableRecord newExe = makeExecutableRecord(manager, hits);
RowKey rowKey = iter2.next();
manager.cacheExecutableByRow(newExe, rowKey);
}
}
View on GitHub (pinned to d5f144c24d)
Solutions
- Inspect the individual sub-response object (subquery) that triggered the failure to read the embedded error type and reason for the specific root cause.
- Ensure no concurrent deletion operations are running against the repository while queries execute.
- Check Elasticsearch cluster health and shard allocation; wait for green before retrying.
- Retry the query after the transient shard issue resolves.
Defensive patterns
Strategy: retry
Try / catch
int retries = 0;
while (true) {
try {
database.query(query);
break;
} catch (ElasticException e) {
if (e.getMessage().contains("Multi-search for exe records failed") && retries < 2) {
retries++;
continue; // transient shard issue — retry after brief pause
}
throw e;
}
} Prevention
- Ensure no concurrent deletions target the executable index while queries run.
- Wait for green cluster health before issuing queries to avoid hitting recovering shards.
- Log the individual msearch sub-response errors for diagnosis when this occurs.
When it happens
Trigger: Called when resolving executable records by document id in bulk via repository_executable/_msearch. After executeBulk returns, each subquery response is checked for a hits key. If a shard is unavailable, the index was deleted, or the document type mapping changed, the sub-response carries an error object instead of hits.
Common situations: An executable document was deleted between id collection and the msearch; a shard is relocating or recovering during the query; the executable index mapping was altered; Elasticsearch returns a 4xx-level error for a specific sub-request.
Related errors
- Could not find hits document
- {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/c1a125faa73463b9.
Report an issue: GitHub.