NationalSecurityAgency/ghidra · error · SQLException

Unknown vector hash

Error message

Unknown vector hash

What it means

Thrown inside H2VectorTable.updateVector() after a successful UPDATE (rc==1) on the vec_hash, but the subsequent SELECT id,count by that same vec_hash returns zero rows. The hash was just written but is no longer found, indicating a data-consistency violation in the H2 vector table between the UPDATE at line 215 and the SELECT at line 229.

Source

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

		s.setInt(1, countDiff);
		s.setLong(2, vecHash);
		int rc = s.executeUpdate();
		if (rc == 0) {
			return insert(countDiff, vec);
		}
		if (rc > 1) {
			throw new SQLException("Unexpected updated row count: " + rc);
		}

		s = select_id_by_hash_stmt.prepareIfNeeded(() -> db
				.prepareStatement("SELECT id, count FROM " + TABLE_NAME + " WHERE vec_hash = ?"));
		s.setLong(1, vecHash);

		long id;
		int count;
		try (ResultSet rs = s.executeQuery()) {
			if (!rs.next()) {
				throw new SQLException("Unknown vector hash");
			}
			id = rs.getLong(1);
			count = rs.getInt(2);
		}
		vectorStore.update(
			new VectorStoreEntry(id, vec, count, vectorFactory.getSelfSignificance(vec)));
		return id;
	}

	/**
	 * Update vector table entry with the specified countDiff.  Record will be removed
	 * if reduced vector count less-than-or-equal zero. 
	 * @param id vector ID
	 * @param countDiff positive vector count reduction
	 * @return 0 if decrement short of 0, return 1 if record was removed, return
	 *         -1 if there was a problem
	 * @throws SQLException if an error occurs
	 */

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Ensure single-writer access to the H2 database file during ingest (BSim H2 file DBs are not designed for concurrent writes).
  2. Verify the BSim database was created with the same Ghidra version and vector factory configuration as the code reading it.
  3. Run a database consistency check or rebuild the index using the 'rebuildindex' BSim command.
  4. If the database is corrupted, recreate it using 'createdatabase' and re-ingest signatures.

Example fix

// before: concurrent updates from multiple threads can interleave
ExecutorService pool = Executors.newFixedThreadPool(4);
for (var vec : vectors) {
    pool.submit(() -> table.updateVector(vec, 1));
}

// after: serialize writes to avoid interleaved UPDATE/SELECT
for (var vec : vectors) {
    table.updateVector(vec, 1); // single-threaded, or use a connection-per-thread model
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure single-writer access before calling updateVector
if (!isSingleWriter(db.getConnection())) {
    throw new IllegalStateException("Concurrent write detected on BSim H2 database");
}
table.updateVector(vec, countDiff);

Try / catch

try {
    long id = table.updateVector(vec, countDiff);
} catch (SQLException e) {
    if (e.getMessage().contains("Unknown vector hash")) {
        // Row vanished between UPDATE and SELECT — likely concurrency or hash mismatch
        // Retry once under a fresh transaction, or fall back to insert
        table.insert(countDiff, vec);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Concurrent modification of H2VectorTable between the UPDATE (line 210-215) and the SELECT (line 223-234): another thread or transaction deletes the row. Alternatively, vec.calcUniqueHash() returns inconsistent values across calls due to a vector factory version mismatch or corrupted vector data.

Common situations: Running multi-threaded BSim ingest against a shared H2 file database without proper transaction isolation; migrating a BSim database between Ghidra versions where the hash algorithm changed; database file corruption after an unclean shutdown.

Related errors


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