NationalSecurityAgency/ghidra · error · SQLException

Bad vectable rowid

Error message

Bad vectable rowid

What it means

Thrown by PostgresFunctionDatabase.queryVectorId() when a SELECT by the given row id returns no rows from the vectable. This means no vector record exists with the requested id — the id is stale, was already deleted, or never existed.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/PostgresFunctionDatabase.java:539

			}
			SimilarityVectorResult simres = new SimilarityVectorResult(frec);
			simres.addNotes(resultset);
			response.totalmatch += simres.getTotalCount();
			if (simres.getTotalCount() == 1) {
				response.uniquematch += 1;
			}
			response.result.add(simres);
		}
	}

	@Override
	protected VectorResult queryVectorId(long id) throws SQLException {
		PreparedStatement s = selectVectorByRowIdStatement.prepareIfNeeded(() -> initConnection()
				.prepareStatement("SELECT id,count,vec FROM vectable WHERE id = ?"));
		s.setLong(1, id);
		try (ResultSet rs = s.executeQuery()) {
			if (!rs.next()) {
				throw new SQLException("Bad vectable rowid");
			}
			VectorResult rowres;
			try {
				rowres = new VectorResult();
				rowres.vectorid = rs.getLong(1);
				rowres.hitcount = rs.getInt(2);
				rowres.vec = vectorFactory.restoreVectorFromSql(rs.getString(3));
			}
			catch (final IOException e) {
				throw new SQLException(e.getMessage());
			}

			return rowres;
		}

	}

	@Override

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Verify the vector id is valid and the corresponding vectable row still exists before querying.
  2. If the row may have been deleted, handle the missing-row case gracefully in the caller.
  3. Ensure no concurrent process is deleting vectors that this query depends on.

Example fix

// before
VectorResult vr = db.queryVectorId(id); // throws "Bad vectable rowid" if deleted

// after — guard against stale id
// (check existence first, or catch SQLException)
try {
    VectorResult vr = db.queryVectorId(id);
} catch (SQLException e) {
    if (e.getMessage().contains("Bad vectable rowid")) {
        // vector was deleted; handle gracefully
    } else throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the vector id still exists before querying
// (requires a separate existence check or tracking deletion state)
// If you have access to a connection:
// SELECT 1 FROM vectable WHERE id = ?

Try / catch

try {
    VectorResult vr = db.queryVectorId(id);
} catch (SQLException e) {
    if (e.getMessage().equals("Bad vectable rowid")) {
        // vector was deleted or id is invalid; handle gracefully
        return null;
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling queryVectorId(id) with an id that does not correspond to any row in vectable. This occurs when a previously obtained vector id references a row that was subsequently removed (e.g. by deleteVectors reducing count to zero), or when an invalid/zero id is passed.

Common situations: A SignatureRecord's vector id was deleted by a concurrent or prior operation. A reference to a vector id was persisted and the underlying row was cleaned up. An off-by-one or uninitialized id (e.g. 0 or -1) is passed accidentally.

Related errors


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