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
- Ensure single-writer access to the H2 database file during ingest (BSim H2 file DBs are not designed for concurrent writes).
- Verify the BSim database was created with the same Ghidra version and vector factory configuration as the code reading it.
- Run a database consistency check or rebuild the index using the 'rebuildindex' BSim command.
- 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
- Ensure only one thread writes to the H2 database file at a time.
- Use H2 database-level locking (e.g., AUTO_SERVER=FALSE, file_lock=fs) to prevent multi-process access.
- Verify vector factory configuration matches the database's hash algorithm before ingesting.
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.