NationalSecurityAgency/ghidra · warning · DatabaseNonFatalException

Already inserted

Error message

Already inserted

What it means

After inserting every executable in an InsertRequest, if newExecutable stayed false (no non-library executable was newly inserted -- each was already present / non-fatal) it throws DatabaseNonFatalException("Already inserted"), signalling the whole insert was a no-op.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/ElasticDatabase.java:3064

			info.settings = query.manage.getSettings();
			writeBasicInfo(0, 0); // Save off the settings associated with this first insert
		}
		ResponseInsert response = query.insertresponse;
		if ((query.repo_override != null) && (query.repo_override.length() != 0)) {
			query.manage.overrideRepository(query.repo_override, query.path_override);
		}
		// Insert each executable in turn
		boolean newExecutable = false;
		for (ExecutableRecord erec : query.manage.getExecutableRecordSet()) {
			if (erec.isLibrary()) {
				insertLibrary(query.manage, erec);
			}
			else if (insertExe(query.manage, erec)) {
				newExecutable = true;
			}
		}
		if (!newExecutable) {
			throw new DatabaseNonFatalException("Already inserted");
		}
		response.numexe = query.manage.getExecutableRecordSet().size();
		response.numfunc = query.manage.numFunctions();
	}

	/**
	 * Entry point for the Elasticsearch version of QueryPair command:
	 *   Query for pairs functions in the database, and compute the similarity
	 *   and significance of their feature vectors
	 * @param query is command parameters
	 * @throws ElasticException for communication problems with the server
	 * @throws LSHException for problems adding records to the response
	 */
	private void fdbQueryPair(QueryPair query) throws ElasticException, LSHException {
		ResponsePair response = query.pairResponse;

		double aveSim = 0.0;
		double aveSimSquare = 0.0;

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Treat as expected: catch DatabaseNonFatalException and continue.
  2. Drop the executables first to force a real re-insert.
  3. Track insert state to skip sets known to be already present.

Example fix

// before
try { db.insert(req); }
catch (Exception e) { throw new RuntimeException(e); } // crashes on benign re-ingest
// after
try { db.insert(req); }
catch (DatabaseNonFatalException e) { log.info("No new executables: {}", e.getMessage()); }
Defensive patterns

Strategy: try-catch

Validate before calling

// Skip the round-trip if every md5 is already present.
boolean anyNew = req.manage.getExecutableRecordSet().stream()
    .anyMatch(e -> !db.hasExecutableForMd5(e.getMd5()));
if (!anyNew) { log.info("Already inserted; skipping"); return; }

Try / catch

try { db.insert(req); }
catch (DatabaseNonFatalException e) { /* entire batch already present */ }
catch (LSHException | ElasticException e) { throw e; }

Prevention

When it happens

Trigger: Re-ingesting an executable set where every non-library executable already exists in the database.

Common situations: Re-running an ingest pipeline over unchanged artifacts; an idempotent CI ingest step.

Related errors


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