NationalSecurityAgency/ghidra · error · SQLException

failed to delete H2-file database

Error message

failed to delete H2-file database: {}

What it means

Thrown as an SQLException by H2FileFunctionDatabase.dropDatabase() when fileDs.delete() returns false after the database has been verified as a valid BSim database and the data source has been disposed. The H2 file data source was unable to delete the underlying database files from disk.

Solutions

  1. Check for processes holding the file open (lsof on Linux, Resource Monitor on Windows) and close them.
  2. Verify file system write/delete permissions on the database directory.
  3. Remove any stale H2 lock files (.lock.db, .lock.db.trace.db) manually after ensuring no process is active.
  4. Retry the drop after a brief delay if a transient OS lock (backup/AV scan) is the cause.
  5. As a last resort, shut down all processes and manually delete the database files from the OS.

Example fix

// before
db.dropDatabase(); // delete() returns false

// after
try {
    db.dropDatabase();
} catch (SQLException e) {
    if (e.getMessage().contains("failed to delete")) {
        // clear stale locks and retry
        Files.deleteIfExists(dbPath.resolve("bsim.lock.db"));
        Thread.sleep(1000);
        Files.deleteIfExists(dbPath);
    } else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check file writability/deletability before drop
if (!Files.isWritable(dbPath)) {
    throw new IllegalStateException(
        "Database file is not writable/deletable: " + dbPath);
}
// Check no external process holds the file (Linux)
// (platform-specific; on Linux use lsof, on Windows use Resource Monitor)

Try / catch

try {
    database.dropDatabase();
} catch (SQLException e) {
    if (e.getMessage().startsWith("failed to delete H2-file database:")) {
        // Clear locks and retry with OS-level deletion
        Path lockFile = dbPath.resolveSibling(dbPath.getFileName() + ".lock.db");
        Files.deleteIfExists(lockFile);
        Files.deleteIfExists(dbPath);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Occurs when the BSim tables are confirmed present, fileDs.dispose() succeeds (disconnecting the pool), but fileDs.delete() returns false. This happens due to: OS-level file locking by another process, insufficient file system permissions, read-only file system, or the file being held open by an external process (antivirus, backup, IDE).

Common situations: Antivirus or backup software is scanning the database file. Another process (different JVM, file manager) has the file open. Running on a read-only or permission-restricted file system. The H2 lock file wasn't properly cleaned up. Network-mounted file system with delayed lock release.

Related errors


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

Appendix: source

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

			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));
				}
			}
		}

		// Spot check for a few BSim table names that always exist
		if (!tableNames.contains("keyvaluetable") || !tableNames.contains("desctable") ||
			!tableNames.contains("weighttable")) {
			throw new SQLException("attempted to drop non-BSim database");
		}

		fileDs.dispose(); // disconnect before deleting database

		BSimServerInfo serverInfo = fileDs.getServerInfo();
		if (!fileDs.delete()) {
			throw new SQLException("failed to delete H2-file database: " + serverInfo);
		}

		Msg.info(this, "Deleted BSim H2-file database: " + serverInfo);

	}

	/**
	 * Create vector map which maps vector ID to {@link VectorStoreEntry}
	 * @return vector map
	 * @throws SQLException if error occurs while reading map data
	 */
	public Map<Long, VectorStoreEntry> readVectorMap() throws SQLException {
		return vectorTable.readVectors();
	}

	@Override
	protected int deleteVectors(long id, int countdiff) throws SQLException {
		return vectorTable.deleteVector(id, countdiff);

View on GitHub (pinned to d5f144c24d)