NationalSecurityAgency/ghidra · error · SQLException

Bad exetable rowid

Error message

Bad exetable rowid

What it means

Thrown by ExeTable.querySingleExecutableId when a SELECT by id returns no rows (rs.next() is false). The requested exetable row id does not exist. This is the read-side analog of error 808: a lookup for an executable that is not present.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/client/tables/ExeTable.java:317

		}
		return count;
	}

	/**
	 * Query for a single executable based on its exetable -id-
	 * 
	 * @param id the exetable id
	 * @return the executable row
	 * @throws SQLException if there is a problem creating or executing the query
	 */
	public ExecutableRow querySingleExecutableId(long id) throws SQLException {

		PreparedStatement s =
			selectByIdStatement.prepareIfNeeded(() -> db.prepareStatement(SELECT_BY_ID_STMT));
		s.setInt(1, (int) id);
		try (ResultSet rs = s.executeQuery()) {
			if (!rs.next()) {
				throw new SQLException("Bad exetable rowid");
			}
			ExecutableRow row = new ExecutableRow();
			extractExecutableRow(rs, row);
			return row;
		}
	}

	/**
	 * Return the executable with matching md5 (if any)
	 * 
	 * @param md5 the md5 hash to query
	 * @return the ExecutableRow data or null
	 * @throws SQLException if there is a problem creating or executing the query
	 */
	public ExecutableRow queryMd5ExeMatch(String md5) throws SQLException {

		PreparedStatement s =
			selectByMd5Statement.prepareIfNeeded(() -> db.prepareStatement(SELECT_BY_MD5_STMT));

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Confirm the id was obtained from the same live database.
  2. Use a broader query (e.g., by md5) to locate the executable if the id is uncertain.
  3. Guard long ids against int overflow before calling (id must fit in 32-bit signed range).
  4. Recover or rebuild the database if rows are missing due to corruption.

Example fix

// before
ExecutableRow row = table.querySingleExecutableId(id);

// after
if (id > Integer.MAX_VALUE || id < Integer.MIN_VALUE) {
    throw new IllegalArgumentException("exe id out of int range: " + id);
}
ExecutableRow row = table.querySingleExecutableId(id);
Defensive patterns

Strategy: validation

Validate before calling

// Guard long ids against int truncation and absence before lookup.
if (id < Integer.MIN_VALUE || id > Integer.MAX_VALUE) {
    throw new IllegalArgumentException("exe id out of int range: " + id);
}
// Optionally check existence first via a count query.

Try / catch

try {
    return exeTable.querySingleExecutableId(id);
} catch (SQLException e) {
    if (e.getMessage().contains("Bad exetable rowid")) {
        return exeTable.queryExecutableMd5(md5); // fallback lookup
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling querySingleExecutableId(id) with an id not present in exetable. The executable was deleted, the id is foreign, or the database is missing the row. The internal setInt(1, (int) id) cast means a long id outside int range truncates and will not match.

Common situations: Looking up an executable by a stale or cross-database id. Querying after a deletion. Int-truncation of large ids. Partial database restore missing exetable rows.

Related errors


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