NationalSecurityAgency/ghidra · error · LSHException

{lastError.message}

Error message

{lastError.message}

What it means

Thrown by BulkSignatures.installTags when an InstallTagRequest fails at the database level. The method calls establishQueryServerConnection to connect, then executes the tag-install query; if the query returns null, it reads the underlying BSimError from querydb.getLastError() and wraps its message in an LSHException. The actual root cause is inside that BSimError — the tag may already exist, the connection may have dropped, or the server rejected the operation.

Source

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

		Msg.info(this, buf.toString());
	}

	/**
	 * Performs the work of inserting a new function tag name into the database. This 
	 * will build the query object, establish the database connection, and perform the query.
	 * 
	 * @param tagName the tag name to insert
	 * @throws IOException if there's an error establishing the database connection
	 * @throws LSHException if there's an error issuing the query
	 */
	public void installTags(String tagName) throws IOException, LSHException {
		DatabaseInformation info = establishQueryServerConnection(false);
		InstallTagRequest req = new InstallTagRequest();
		req.tag_name = dequoteString(tagName);
		ResponseInfo resp = req.execute(querydb);
		if (resp == null) {
			BSimError lastError = querydb.getLastError();
			throw new LSHException(lastError.message);
		}
		info = resp.info;

		StringBuilder buf = new StringBuilder();
		buf.append("BSim Database ");
		buf.append(info.databasename);
		buf.append(" now contains:\n");
		formatFunctionTags(info.functionTags, buf);

		// TODO: Should this output differ for command-line vs workbench? debug only?
		Msg.info(this, buf.toString());
	}

	protected static int readQueryPairs(XmlPullParser parser, int count, List<PairInput> pairs) {
		for (int i = 0; i < count; ++i) {
			if (!parser.peek().isStart()) {
				return i;
			}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Check whether the tag already exists by running a 'queryinfo' command against the same database before attempting install.
  2. Verify the BSim server URL and credentials in the connection configuration — re-run with a known-good connect string.
  3. Inspect the BSimError returned by querydb.getLastError() in a debugger or log to read the exact server-side message; it is not surfaced in the thrown exception beyond lastError.message.
  4. If the tag genuinely should not exist, drop it first or use the appropriate overwrite/admin path.

Example fix

// before
public void installTags(String tagName) throws IOException, LSHException {
    DatabaseInformation info = establishQueryServerConnection(false);
    InstallTagRequest req = new InstallTagRequest();
    req.tag_name = dequoteString(tagName);
    ResponseInfo resp = req.execute(querydb);
    if (resp == null) {
        BSimError lastError = querydb.getLastError();
        throw new LSHException(lastError.message);
    }
    ...
}

// after — pre-check and richer error
public void installTags(String tagName) throws IOException, LSHException {
    DatabaseInformation info = establishQueryServerConnection(false);
    if (info.functionTags != null && info.functionTags.contains(tagName)) {
        Msg.warn(this, "Tag '" + tagName + "' already exists; skipping install.");
        return;
    }
    InstallTagRequest req = new InstallTagRequest();
    req.tag_name = dequoteString(tagName);
    ResponseInfo resp = req.execute(querydb);
    if (resp == null) {
        BSimError lastError = querydb.getLastError();
        throw new LSHException("InstallTag failed for '" + tagName + "': " + lastError.message);
    }
    ...
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check if the tag already exists before installing
DatabaseInformation info = querydb.getInfo();
if (info.functionTags != null && info.functionTags.contains(tagName)) {
    // Tag exists; skip or handle accordingly
    return;
}

Type guard

// No type guard applicable — tagName is a String parameter.
// Validate non-blank before calling installTags:
if (tagName == null || tagName.trim().isEmpty()) {
    throw new IllegalArgumentException("tagName must not be blank");
}

Try / catch

try {
    bulk.installTags(tagName);
} catch (LSHException e) {
    if (e.getMessage().contains("already exists")) {
        // benign — tag was already present
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling installTags(tagName) against a live BSim server where the InstallTagRequest.execute(querydb) call returns null. This happens when the server reports an error (e.g., tag already exists, authentication failure, or a database constraint violation). The dequoteString preprocessing does not guard against duplicates.

Common situations: Running 'bsim installtag' on a tag name that already exists in the target database; pointing at a PostgreSQL or Elasticsearch BSim backend whose connection credentials are wrong or expired; network interruption between the client and the BSim server during the query.

Related errors


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