{"record":{"id":"ab4d0e36b703adb9","repo":"NationalSecurityAgency/ghidra","slug":"no-function-documents-matching-id-rowid","errorCode":null,"errorMessage":"No function documents matching id=${rowId}","messagePattern":"No function documents matching id=(.+?)","errorType":"exception","errorClass":"ElasticException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java","lineNumber":3458,"sourceCode":"\t * @param manager is the container for the new FunctionDescription\n\t * @param rowId is the document id of the function\n\t * @return the new FunctionDescription\n\t * @throws ElasticException for communication problems with the server\n\t * @throws LSHException for problems adding records to the container\n\t */\n\tprivate FunctionDescription querySingleDescriptionId(DescriptionManager manager, String rowId)\n\t\t\tthrows ElasticException, LSHException {\n\t\tStringBuilder buffer = new StringBuilder();\n\t\tbuffer.append(\"{ \\\"query\\\": { \\\"ids\\\": { \\\"values\\\": [ \\\"\");\n\t\tbuffer.append(rowId);\n\t\tbuffer.append(\"\\\" ] } } }\");\n\t\tJsonObject resp = connection.executeStatement(ElasticConnection.GET, \"executable/_search\",\n\t\t\tbuffer.toString());\n\t\tJsonObject hits = (JsonObject) resp.get(\"hits\");\n\t\tJsonObject totalRec = (JsonObject) hits.get(\"total\");\n\t\tlong total = totalRec.get(\"value\").getAsLong();\n\t\tif (total == 0) {\n\t\t\tthrow new ElasticException(\"No function documents matching id=\" + rowId);\n\t\t}\n\t\tJsonArray hitsArray = (JsonArray) hits.get(\"hits\");\n\t\tJsonObject row = (JsonObject) hitsArray.get(0);\n\t\tJsonObject source = (JsonObject) row.get(\"_source\");\n\t\tJsonObject joinfield = (JsonObject) source.get(\"join_field\");\n\t\tString exeId = joinfield.get(\"parent\").getAsString();\n\t\tRowKeyElastic eKey = RowKeyElastic.parseExeIdString(exeId);\n\t\tExecutableRecord exeRec = manager.findExecutableByRow(eKey);\n\t\tif (exeRec == null) {\n\t\t\tList<RowKeyElastic> keyList = new ArrayList<>();\n\t\t\tkeyList.add(eKey);\n\t\t\tqueryExecutableRecordById(manager, keyList.iterator(), keyList.iterator(), 2);\n\t\t\texeRec = manager.findExecutableByRow(eKey);\n\t\t}\n\t\treturn convertDescriptionRow(row, exeRec, manager, null);\n\t}\n\n\t/**","sourceCodeStart":3440,"sourceCodeEnd":3476,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java#L3440-L3476","documentation":"Thrown by ElasticDatabase.querySingleDescriptionId when an Elasticsearch _search by document id against the 'executable' index returns zero hits. The method expects exactly one function document for the given rowId (a BSim function document _id); a missing document means the BSim index is out of sync with the in-memory DescriptionManager or the id was stale/invalid. It is an ElasticException, indicating a server-side data-consistency problem rather than a caller bug.","triggerScenarios":"Calling fillinChildren / a callgraph or description query that resolves a cached RowKey to a function id that no longer exists in the Elasticsearch index. Happens when the DB was modified (re-indexed, documents deleted) while a query session still holds old ids, or when an id string is malformed so it matches no document.","commonSituations":"Concurrent re-ingest of an executable that deleted and re-created function documents; pointing a client at the wrong ES cluster whose schema/data differs; a race where the parent executable record exists but its child function documents were not yet indexed.","solutions":["Re-query the parent executable record (queryExecutableRecordById) to refresh ids, then retry the description lookup.","Verify the Elasticsearch cluster/index the client points at matches the one that produced the cached ids; reconnect with the correct URL.","If hit during callgraph expansion, ensure the database was ingested with trackcallgraph enabled and documents were committed (refresh) before querying.","Treat as non-fatal where possible: log the rowId and skip that function rather than aborting the whole query."],"exampleFix":"// before\nJsonObject resp = connection.executeStatement(ElasticConnection.GET, \"executable/_search\", buffer.toString());\n// ... if total == 0 throw\n// after: re-fetch parent and retry once, else skip\nif (total == 0 && !manager.findExecutableByRow(parentKey).wasRefreshed()) {\n    manager.invalidate(parentKey);\n    return querySingleDescriptionId(manager, rowId);\n}","handlingStrategy":"try-catch","validationCode":"// before resolving a cached function id\n// confirm the parent executable still lists this function id\nif (!cachedExecutableRecord.hasFunctionId(rowId)) {\n    // refresh or skip\n    return null;\n}","typeGuard":null,"tryCatchPattern":"try {\n    return querySingleDescriptionId(manager, rowId);\n} catch (ElasticException e) {\n    if (e.getMessage().startsWith(\"No function documents matching id=\")) {\n        log.warning(\"Stale function id \" + rowId + \"; skipping\");\n        return null; // skip rather than abort the whole query\n    }\n    throw e;\n}","preventionTips":["Do not hold cached function ids across a re-ingest that deletes/recreates documents.","After bulk re-ingest, force an ES index refresh before querying.","Point clients at the cluster that owns the ids; never mix clusters."],"tags":["bsim","elasticsearch","data-integrity","not-found","callgraph"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}