NationalSecurityAgency/ghidra · critical · ElasticException
Mismatch in metaid
Error message
Mismatch in metaid
What it means
Internal consistency check in fetchVectorCounts: after a meta/_mget multi-get, each returned document's base64 _id is decoded and compared to the VectorResult.vectorid it should correspond to. A mismatch means the docs came back in a different order or with different ids than requested. ES _mget is supposed to preserve request order, so this indicates corruption, a non-ES backend, or a proxy/gateway that reordered the response.
Source
Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java:644
vecRes = iter1.next();
buffer.append(", \"");
Base64Lite.encodeLongBase64(buffer, vecRes.vectorid);
buffer.append('\"');
}
buffer.append(" ] }");
JsonObject resp =
connection.executeStatement(ElasticConnection.GET, "meta/_mget", buffer.toString());
JsonArray docs = (JsonArray) resp.get("docs");
for (int i = 0; i < maxDocuments; ++i) {
if (!iter2.hasNext()) {
break;
}
vecRes = iter2.next();
JsonObject oneResp = (JsonObject) docs.get(i);
String matchId = oneResp.get("_id").getAsString();
long matchIdVal = Base64Lite.decodeLongBase64(matchId);
if (matchIdVal != vecRes.vectorid) {
throw new ElasticException("Mismatch in metaid");
}
JsonElement source = oneResp.get("_source");
if (ElasticConnection.isNull(source)) {
throw new ElasticException("meta document does not exist for id=" + matchId);
}
long count = ((JsonObject) source).get("count").getAsLong();
totalCount += count;
vecRes.hitcount = (int) count;
}
return totalCount;
}
/**
* Fetch vectors in bulk from the database, given a list of VectorResults with the vector ids
* The vector documents are queried, then the resulting LSHVector objects are filled
* in for the VectorResults by parsing the documents. Two iterators pointing to the same list
* of VectorResults are required, one for building the query, one for filling in the LSHVectors.
* If no exception is thrown, both iterators are advanced the same number of times.View on GitHub (pinned to d5f144c24d)
Solutions
- Reproduce with a direct curl _mget against ES (bypassing any proxy) to confirm ES itself preserves order; if it does, the proxy is the culprit.
- Match the VectorResult list and the docs array by id instead of by position when reshaping results, or re-run the query in smaller batches.
- If corruption is confirmed, reindex the affected BSim repository from a known-good source.
Example fix
// before: relies on positional order returned by _mget
// (internal in fetchVectorCounts; no direct caller fix)
// after (defensive, if you wrap the call): retry once, then fall back to single-doc gets
try { return db.fetchVectorCounts(...); }
catch (ElasticException e) { if (e.getMessage().equals("Mismatch in metaid")) return fetchVectorCountsOneByOne(...); throw e; } Defensive patterns
Strategy: fallback
Validate before calling
// Cannot be pre-validated from outside; it is an internal ordering assertion.
// Mitigate by issuing the multi-get directly (bypassing any reordering proxy) for verification:
public static boolean mgetPreservesOrder(String url, String index) throws Exception {
HttpURLConnection h = (HttpURLConnection) URI.create(url + "/" + index + "/_mget").toURL().openConnection();
h.setRequestMethod("GET"); h.setDoOutput(true);
try (Writer w = new OutputStreamWriter(h.getOutputStream())) { w.write("{\"ids\":[\"AAAB\",\"AAAC\"]}"); }
JsonObject r = JsonParser.parseReader(new InputStreamReader(h.getInputStream())).getAsJsonObject();
return ((JsonArray) r.get("docs")).get(0).getAsJsonObject().get("_id").getAsString().equals("AAAB");
} Try / catch
try {
return db.fetchVectorCounts(it1, it2, n);
} catch (ElasticException e) {
if (!e.getMessage().equals("Mismatch in metaid")) throw e;
// fall back to per-id single gets, which are not order-dependent
return fetchVectorCountsSingly(it1, n);
} Prevention
- Bypass reordering proxies/gateways for the ES _mget route.
- Keep BSim talking to standard Elasticsearch; verify _mget order after version upgrades.
- If mismatches recur, suspect index corruption and plan a reindex.
When it happens
Trigger: fetchVectorCounts iterating VectorResults after a meta/_mget where docs[i]._id decodes to a value != the i-th requested vectorid. Caused by a man-in-the-middle/proxy reordering docs, a non-ES service answering _mget, a buggy ES plugin, or index corruption returning wrong ids.
Common situations: ES behind a gateway that rewrites/reorders multi-get responses; talking to an OpenSearch/plugin variant whose _mget semantics differ; rare index corruption after a hardware/replication fault.
Related errors
- meta document does not exist for id=
- Mismatch in vectorid
- vector document does not exist for id=
- 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/a326c6f996b0e758.
Report an issue: GitHub.