{"record":{"id":"c2b50fcfea4fad30","repo":"NationalSecurityAgency/ghidra","slug":"exespecifier-must-provide-either-md5-or-name-c2b50f","errorCode":null,"errorMessage":"ExeSpecifier must provide either md5 or name","messagePattern":"ExeSpecifier must provide either md5 or name","errorType":"exception","errorClass":"LSHException","httpStatus":null,"severity":"error","filePath":"Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java","lineNumber":426,"sourceCode":"\t * Query for a single executable given uniquely specifying information (ExeSpecifier).\n\t * The exe document is retrieved from the database and parsed into an ExecutableRecord object.\n\t * @param specifier is the uniquely specifying info about the executable\n\t * @param manager is container for the final ExecutableRecord\n\t * @return the matching ExecutableRecord or null if none is found\n\t * @throws LSHException if there are problems adding the queried record to the container\n\t * @throws ElasticException for communication problems with the server\n\t */\n\tprivate ExecutableRecord findSingleExecutable(ExeSpecifier specifier,\n\t\t\tDescriptionManager manager) throws LSHException, ElasticException {\n\t\tif (specifier.exemd5 != null && specifier.exemd5.length() != 0) {\n\t\t\tJsonObject row = queryMd5ExeMatch(specifier.exemd5);\n\t\t\tif (row == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn makeExecutableRecord(manager, row);\n\t\t}\n\t\tif (StringUtils.isEmpty(specifier.exename)) {\n\t\t\tthrow new LSHException(\"ExeSpecifier must provide either md5 or name\");\n\t\t}\n\t\treturn querySingleExecutable(manager, specifier.exename, specifier.arch,\n\t\t\tspecifier.execompname);\n\t}\n\n\t/**\n\t * Query for a single executable given uniquely specifying information (ExeSpecifier).\n\t * A cache map is checked first for a previously recovered ExecutableRecord object.\n\t * If not in the cache, the database is searched. If the executable is found, the ExecutableRecord\n\t * is parsed from the database document, put into the cache, and returned to the user.\n\t * @param specifier is the uniquely specifying info about the executable\n\t * @param manager is container for the final ExecutableRecord\n\t * @param nameMap is the cache of previously recovered records\n\t * @return the matching ExecutableRecord or null if none is found\n\t * @throws LSHException if there are problems adding the queried record to the container\n\t * @throws ElasticException for communication problems with the server\n\t */\n\tprivate ExecutableRecord findSingleExeWithMap(ExeSpecifier specifier,","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java#L408-L444","documentation":"Thrown as LSHException (not ElasticException) by findSingleExecutable when an ExeSpecifier has neither an md5 (exemd5 null/empty) nor a name (exename empty). It is a caller-contract violation: the lookup needs at least one identifier to proceed. ExeSpecifier defaults all fields to empty strings, so an untouched specifier triggers it.","triggerScenarios":"Calling findSingleExecutable (directly or via findSingleExeWithMap / the public query path) with an ExeSpecifier whose exemd5 is empty AND exename is empty. Arises from deserializing an <exe> XML block missing both <md5> and <name>, or building a specifier from a query whose md5sum and name_exec were both blank (see ElasticDatabase ~line 3543-3546).","commonSituations":"A BSim query request with no executable identifier filled in; malformed client XML missing the md5/name elements; programmatic specifier built but fields never assigned because the upstream md5/name were null.","solutions":["Before calling, ensure the ExeSpecifier has a non-empty exemd5 OR a non-empty exename; prefer md5 when available.","If the specifier is built from a query object, validate query.md5sum / query.name_exec upstream and reject blank values with a clear error.","When restoring from XML, treat a missing <md5> and missing/blank <name> as an invalid request."],"exampleFix":"// before\nExeSpecifier spec = new ExeSpecifier();\nExecutableRecord r = db.findSingleExecutable(spec, mgr); // throws LSHException\n// after\nExeSpecifier spec = new ExeSpecifier();\nspec.exemd5 = md5 != null ? md5 : \"\";\nspec.exename = name != null ? name : \"\";\nif (spec.exemd5.isEmpty() && spec.exename.isEmpty()) {\n    throw new IllegalArgumentException(\"exe lookup needs an md5 or a name\");\n}\nExecutableRecord r = db.findSingleExecutable(spec, mgr);","handlingStrategy":"validation","validationCode":"public static ExeSpecifier requireIdentifier(ExeSpecifier s) {\n    boolean hasMd5 = s.exemd5 != null && !s.exemd5.isEmpty();\n    boolean hasName = s.exename != null && !s.exename.isEmpty();\n    if (!hasMd5 && !hasName)\n        throw new IllegalArgumentException(\"ExeSpecifier needs a non-empty md5 or name\");\n    return s;\n}","typeGuard":"public static boolean hasIdentifier(ExeSpecifier s) {\n    return s != null && ((s.exemd5 != null && !s.exemd5.isEmpty()) || (s.exename != null && !s.exename.isEmpty()));\n}","tryCatchPattern":"try {\n    return db.findSingleExecutable(spec, mgr);\n} catch (LSHException e) {\n    if (e.getMessage().equals(\"ExeSpecifier must provide either md5 or name\"))\n        throw new IllegalArgumentException(\"Caller must set exe md5 or name\", e);\n    throw e;\n}","preventionTips":["ExeSpecifier defaults every field to empty string; never pass a freshly-constructed one unmodified.","When deserializing <exe> XML, reject entries missing both <md5> and <name>.","Prefer the md5 identifier when available for unambiguous lookups."],"tags":["validation","bsim","executable-record","input"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}