NationalSecurityAgency/ghidra · warning · LSHException

Executable category already exists

Error message

Executable category already exists

What it means

Thrown by fdbInstallCategory when the requested category type_name already exists in info.execats (the database's executable category list). BSim prevents duplicate category columns to avoid schema ambiguity. Date columns (isdatecolumn=true) bypass this check.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/AbstractSQLFunctionDatabase.java:2197

	 * @throws SQLException if there is an error issuing the query
	 */
	private void fdbInstallCategory(InstallCategoryRequest query)
			throws LSHException, SQLException {
		ResponseInfo response = query.installresponse;
		if (!CategoryRecord.enforceTypeCharacters(query.type_name)) {
			throw new LSHException("Bad characters in proposed category type");
		}
		if (query.isdatecolumn) {
			info.dateColumnName = query.type_name;
			keyValueTable.insert("datecolumn", info.dateColumnName);
			response.info = info;
			return;
		}
		// Check for existing category
		if (info.execats != null) {
			for (String cat : info.execats) {
				if (cat.equals(query.type_name)) {
					throw new LSHException("Executable category already exists");
				}
			}
		}
		if (info.execats == null) {
			info.execats = new ArrayList<>();
		}
		info.execats.add(query.type_name);
		keyValueTable.writeExecutableCategories(info);
		response.info = info;
	}

	/**
	 * Returns a list of all function tags in the database.
	 * 
	 * @return list of function tags
	 */
	public List<String> getFunctionTags() {
		return info.functionTags;

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Query current categories (info.execats) before installing and skip if the name already exists.
  2. Make install scripts idempotent: check contains() before issuing the request.
  3. Guard concurrent installs with coordination or a pre-check.

Example fix

// before
db.execute(installReq); // may already exist
// after
if (info.execats == null || !info.execats.contains(req.type_name)) {
    db.execute(installReq);
}
Defensive patterns

Strategy: validation

Validate before calling

List<String> existing = db.getDatabaseInformation().execats;
boolean already = existing != null && existing.contains(req.type_name);
if (!already) db.execute(req);

Try / catch

catch (LSHException e) { if (e.getMessage().contains("already exists")) { /* harmless on re-run, skip */ } else throw e; }

Prevention

When it happens

Trigger: Issuing an InstallCategoryRequest for a type_name that is already present in the loaded DatabaseInformation.execats array; re-running an install script without checking existing categories.

Common situations: Idempotent setup scripts that re-run installation; concurrent clients both trying to install the same category; migration tooling that doesn't first query existing categories.

Related errors


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