NationalSecurityAgency/ghidra · error · SQLException

Bad vector table rowid

Error message

Bad vector table rowid

What it means

Thrown as an SQLException by H2VectorTable.queryVectorById() when a SELECT by rowid returns no rows. The method first checks the in-memory vectorStore cache; if not found, it queries the database. If the database also has no row with the given id, it throws this error. This means the vector ID does not exist in either the cache or the table.

Source

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

	/**
	 * Get vector details which correspond to specified vector ID
	 * @param id vector ID
	 * @return vector details
	 * @throws SQLException if error occurs
	 */
	public VectorResult queryVectorById(long id) throws SQLException {

		VectorStoreEntry entry = vectorStore.getVectorById(id);
		if (entry != null) {
			return new VectorResult(id, entry.count(), 0, 0, entry.vec());
		}

		PreparedStatement s = select_by_rowid_stmt.prepareIfNeeded(
			() -> db.prepareStatement("SELECT id,count,vec FROM " + TABLE_NAME + " WHERE id = ?"));
		s.setLong(1, id);
		try (ResultSet rs = s.executeQuery()) {
			if (!rs.next()) {
				throw new SQLException("Bad vector table rowid");
			}
			char[] vectorDecodeBuffer = Base64VectorFactory.allocateBuffer();
			VectorResult rowres;
			try {
				rowres = new VectorResult();
				rowres.vectorid = rs.getLong(1);
				rowres.hitcount = rs.getInt(2);
				Reader r = new StringReader(rs.getString(3));
				rowres.vec = vectorFactory.restoreVectorFromBase64(r, vectorDecodeBuffer);
			}
			catch (final IOException e) {
				throw new SQLException(e.getMessage()); // unexpected for StringReader
			}
			return rowres;
		}
	}

	/**

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Verify the vector ID exists by calling readVectorMap() and checking membership.
  2. Check for concurrent modifications — ensure no process is deleting vectors during the query.
  3. If the ID references a deleted vector, update or remove the orphaned reference in the metadata/description tables.
  4. Rebuild the database if widespread data integrity issues are found.

Example fix

// before
VectorResult res = vectorTable.queryVectorById(id); // throws

// after
Map<Long, VectorStoreEntry> valid = vectorTable.readVectors();
if (!valid.containsKey(id)) {
    Msg.warn(this, "Vector ID " + id + " not found; skipping");
    return null;
}
VectorResult res = vectorTable.queryVectorById(id);
Defensive patterns

Strategy: validation

Validate before calling

// Verify vector ID exists in cache or table before querying
if (vectorStore.getVectorById(id) == null) {
    try (PreparedStatement s = db.prepareStatement(
            "SELECT 1 FROM " + TABLE_NAME + " WHERE id = ?")) {
        s.setLong(1, id);
        try (ResultSet rs = s.executeQuery()) {
            if (!rs.next()) {
                throw new IllegalArgumentException(
                    "Vector ID " + id + " does not exist");
            }
        }
    }
}

Try / catch

try {
    return vectorTable.queryVectorById(id);
} catch (SQLException e) {
    if (e.getMessage().equals("Bad vector table rowid")) {
        // Vector doesn't exist; return null or handle gracefully
        return null;
    }
    throw e;
}

Prevention

When it happens

Trigger: Occurs when queryVectorById(id) is called with an ID that has no matching row in h2_vectable AND is not in the vectorStore cache. This happens when: the ID is from a stale reference (vector was deleted), the ID was never inserted, or there is a data integrity gap between the description/metadata tables and the vector table.

Common situations: A function description references a vector ID that was deleted. Concurrent deletion of vectors while querying. Database migration that updated metadata but not vectors. Using an ID obtained from a different database instance.

Related errors


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