{"record":{"id":"a326c6f996b0e758","repo":"NationalSecurityAgency/ghidra","slug":"mismatch-in-metaid","errorCode":null,"errorMessage":"Mismatch in metaid","messagePattern":"Mismatch in metaid","errorType":"exception","errorClass":"ElasticException","httpStatus":null,"severity":"critical","filePath":"Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java","lineNumber":644,"sourceCode":"\t\t\tvecRes = iter1.next();\n\t\t\tbuffer.append(\", \\\"\");\n\t\t\tBase64Lite.encodeLongBase64(buffer, vecRes.vectorid);\n\t\t\tbuffer.append('\\\"');\n\t\t}\n\t\tbuffer.append(\" ] }\");\n\t\tJsonObject resp =\n\t\t\tconnection.executeStatement(ElasticConnection.GET, \"meta/_mget\", buffer.toString());\n\t\tJsonArray docs = (JsonArray) resp.get(\"docs\");\n\t\tfor (int i = 0; i < maxDocuments; ++i) {\n\t\t\tif (!iter2.hasNext()) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tvecRes = iter2.next();\n\t\t\tJsonObject oneResp = (JsonObject) docs.get(i);\n\t\t\tString matchId = oneResp.get(\"_id\").getAsString();\n\t\t\tlong matchIdVal = Base64Lite.decodeLongBase64(matchId);\n\t\t\tif (matchIdVal != vecRes.vectorid) {\n\t\t\t\tthrow new ElasticException(\"Mismatch in metaid\");\n\t\t\t}\n\t\t\tJsonElement source = oneResp.get(\"_source\");\n\t\t\tif (ElasticConnection.isNull(source)) {\n\t\t\t\tthrow new ElasticException(\"meta document does not exist for id=\" + matchId);\n\t\t\t}\n\t\t\tlong count = ((JsonObject) source).get(\"count\").getAsLong();\n\t\t\ttotalCount += count;\n\t\t\tvecRes.hitcount = (int) count;\n\t\t}\n\t\treturn totalCount;\n\t}\n\n\t/**\n\t * Fetch vectors in bulk from the database, given a list of VectorResults with the vector ids\n\t * The vector documents are queried, then the resulting LSHVector objects are filled\n\t * in for the VectorResults by parsing the documents. Two iterators pointing to the same list\n\t * of VectorResults are required, one for building the query, one for filling in the LSHVectors.\n\t * If no exception is thrown, both iterators are advanced the same number of times.","sourceCodeStart":626,"sourceCodeEnd":662,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java#L626-L662","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: relies on positional order returned by _mget\n// (internal in fetchVectorCounts; no direct caller fix)\n// after (defensive, if you wrap the call): retry once, then fall back to single-doc gets\ntry { return db.fetchVectorCounts(...); }\ncatch (ElasticException e) { if (e.getMessage().equals(\"Mismatch in metaid\")) return fetchVectorCountsOneByOne(...); throw e; }","handlingStrategy":"fallback","validationCode":"// Cannot be pre-validated from outside; it is an internal ordering assertion.\n// Mitigate by issuing the multi-get directly (bypassing any reordering proxy) for verification:\npublic static boolean mgetPreservesOrder(String url, String index) throws Exception {\n    HttpURLConnection h = (HttpURLConnection) URI.create(url + \"/\" + index + \"/_mget\").toURL().openConnection();\n    h.setRequestMethod(\"GET\"); h.setDoOutput(true);\n    try (Writer w = new OutputStreamWriter(h.getOutputStream())) { w.write(\"{\\\"ids\\\":[\\\"AAAB\\\",\\\"AAAC\\\"]}\"); }\n    JsonObject r = JsonParser.parseReader(new InputStreamReader(h.getInputStream())).getAsJsonObject();\n    return ((JsonArray) r.get(\"docs\")).get(0).getAsJsonObject().get(\"_id\").getAsString().equals(\"AAAB\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return db.fetchVectorCounts(it1, it2, n);\n} catch (ElasticException e) {\n    if (!e.getMessage().equals(\"Mismatch in metaid\")) throw e;\n    // fall back to per-id single gets, which are not order-dependent\n    return fetchVectorCountsSingly(it1, n);\n}","preventionTips":["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."],"tags":["elasticsearch","data-integrity","bsim","consistency"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}