NationalSecurityAgency/ghidra · error · SQLException

database in use

Error message

database in use

What it means

Thrown as an SQLException by H2FileFunctionDatabase.dropDatabase() when the database status is Busy or there are active connections to the H2 file data source. H2 file databases use file-level locking, so an active connection prevents safe deletion of the database file.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/file/H2FileFunctionDatabase.java:128

	protected void createDatabase(Configuration config) throws SQLException {
		try {
			super.createDatabase(config);

			Connection db = initConnection();
			try (Statement st = db.createStatement()) {
				vectorTable.create(st);
			}
		}
		catch (final SQLException err) {
			throw new SQLException("Could not create database: " + err.getMessage());
		}
	}

	@Override
	protected void dropDatabase() throws SQLException {

		if (getStatus() == Status.Busy || fileDs.getActiveConnections() != 0) {
			throw new SQLException("database in use");
		}

		close(); // close this instance

		if (!fileDs.exists()) {
			// ignore request and return
			return;
		}

		// Connect to database and examine schema
		HashSet<String> tableNames = new HashSet<>();
		try (Connection c = initConnection(); Statement st = c.createStatement()) {
			try (ResultSet rs = st.executeQuery(
				"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name")) {
				while (rs.next()) {
					tableNames.add(rs.getString(1));
				}
			}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Close all other Ghidra instances or processes that have the database open.
  2. Ensure all prior queries have completed and connections are released before calling dropDatabase().
  3. Call database.close() on the current instance before attempting drop.
  4. If connections are leaked, restart Ghidra to clear them.
  5. On the file system level, check for stale H2 lock files (.lock.db) and remove them if no process is active.

Example fix

// before
db.dropDatabase(); // throws 'database in use'

// after
db.close(); // release this instance's connection
int active = fileDs.getActiveConnections();
if (active > 0) {
    throw new IllegalStateException(
        "Cannot drop: " + active + " active connections remain");
}
db.dropDatabase();
Defensive patterns

Strategy: validation

Validate before calling

// Check active connections before dropping
if (database.getStatus() == Status.Busy) {
    throw new IllegalStateException(
        "Database is Busy; wait for in-progress operations to finish");
}
if (fileDs.getActiveConnections() != 0) {
    throw new IllegalStateException(
        fileDs.getActiveConnections() + " active connections; close them first");
}

Try / catch

try {
    database.dropDatabase();
} catch (SQLException e) {
    if (e.getMessage().equals("database in use")) {
        // Close this instance, wait, and retry
        database.close();
        Thread.sleep(2000);
        database.dropDatabase();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Occurs when dropDatabase() is called while getActiveConnections() != 0 or getStatus() == Status.Busy. This happens when: another Ghidra instance or thread has the database open, a prior query hasn't released its connection, or the database is mid-operation.

Common situations: A second Ghidra window has the same H2 BSim database open. A long-running BSim query is in progress. The previous database connection wasn't properly closed (connection leak). Background tasks or headless scripts are still using the database.

Related errors


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