NationalSecurityAgency/ghidra · error · LSHException

Could not determine unique executable

Error message

Could not determine unique executable

What it means

Thrown by doDumpSigs when the QueryName response has uniqueexecutable set to false. This means the query matched zero or more than one executable record, so the system cannot determine which one to dump signatures for. The method needs exactly one match to proceed.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/ingest/BulkSignatures.java:996

	 * @param resultFolder the folder where the results will be stored
	 * @param query the query object containing the params of the query
	 * @throws IOException if there's an error establishing the database connection
	 * @throws LSHException if there's an error issuing the query
	 */
	protected void doDumpSigs(File resultFolder, QueryName query) throws IOException, LSHException {
		if (!resultFolder.isDirectory()) {
			throw new IOException(resultFolder.getAbsolutePath() + " is not a valid directory");
		}

		DatabaseInformation info = establishQueryServerConnection(true);
		query.fillinCallgraph = info.trackcallgraph;
		ResponseName responseName = query.execute(querydb);
		if (responseName == null) {
			BSimError lastError = querydb.getLastError();
			throw new LSHException(lastError.message);
		}
		if (!responseName.uniqueexecutable) {
			throw new LSHException("Could not determine unique executable");
		}
		ExecutableRecord exe;
		if (!StringUtils.isAllBlank(query.spec.exemd5)) {
			exe = responseName.manage.findExecutable(query.spec.exemd5);
		}
		else {
			exe = responseName.manage.findExecutable(query.spec.exename, query.spec.arch,
				query.spec.execompname);
		}
		String basename = "sigs_" + exe.getMd5();
		File sigFile = new File(resultFolder, basename);

		try (FileWriter writer = new FileWriter(sigFile)) {
			responseName.manage.saveXml(writer);
		}
	}

	protected File establishTemporaryDirectory(String xmldir) throws IOException {

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Query by md5 instead of name — md5 is unique by definition.
  2. If querying by name, also provide arch and execompname to narrow the match.
  3. Run a QueryName or queryinfo first to see how many executables match, then disambiguate.
  4. Verify the executable was actually ingested into this BSim database.

Example fix

// before
if (!responseName.uniqueexecutable) {
    throw new LSHException("Could not determine unique executable");
}

// after — report what matched
if (!responseName.uniqueexecutable) {
    int count = responseName.manage.numExecutables();
    throw new LSHException("Could not determine unique executable (matched " +
        count + " records). Narrow by md5, or add arch/compiler qualifiers.");
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check uniqueness by running a count query
QueryName precheck = new QueryName();
precheck.spec.exename = name;
precheck.spec.arch = arch;
precheck.spec.execompname = compiler;
ResponseName preResp = precheck.execute(querydb);
if (preResp != null && !preResp.uniqueexecutable) {
    int count = preResp.manage.numExecutables();
    throw new IllegalStateException(
        "Name '" + name + "' matched " + count + " executables. " +
        "Provide md5 or add arch/compiler qualifiers.");
}

Type guard

// Check the response before doDumpSigs proceeds to the uniqueexecutable check
public static boolean isUniqueMatch(ResponseName resp) {
    return resp != null && resp.uniqueexecutable;
}

Try / catch

try {
    bulk.doDumpSigs(resultFolder, query);
} catch (LSHException e) {
    if (e.getMessage().contains("unique executable")) {
        // Query by md5 instead of name for uniqueness
        query.spec.exemd5 = resolvedMd5;
        query.spec.exename = null;
        bulk.doDumpSigs(resultFolder, query);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Querying by name when multiple executables share that name (common for generic names); querying by md5 that doesn't exist in the database (uniqueexecutable is false for empty results); querying by name without specifying architecture or compiler to disambiguate.

Common situations: Dumping by name 'libfoo.so' when multiple versions exist; the executable was never ingested into the database; name matches across different architectures; md5 hash has a typo.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/eeb8470965581ad5. Report an issue: GitHub.