apache/cassandra · error · RuntimeException
Invalid row " + row + " in table: " + countsMetricsTableName
Error message
Invalid row " + row + " in table: " + countsMetricsTableName
What it means
getCountsMetricsFromVtable reads rows from the CIDRFilteringMetrics counts virtual table using a prepared SELECT. Each row is expected to carry the name and value columns defined by CIDRFilteringMetricsCountsTable; if either is absent the row cannot be interpreted, so a RuntimeException identifies the malformed row and table.
Solutions
- Verify all nodes run the same Cassandra version so the CIDRFilteringMetrics virtual table schema matches the code expectations.
- Re-run the query; transient row materialization issues may resolve.
- Inspect the row's columns (print row.columns()) to see which expected column is missing and adjust the SELECT statement to include it.
- If this persists, file/consult a Cassandra JIRA; a missing column in a system-managed virtual table indicates an internal bug, not user error.
Defensive patterns
Strategy: try-catch
Validate before calling
for (UntypedResultSet.Row row : result)
if (!row.has("name") || !row.has("value"))
throw new IllegalStateException("CIDR counts table schema mismatch; check node versions");
Try / catch
try {
metrics = getCountsMetricsFromVtable();
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Invalid row")) {
logger.warn("CIDR counts metrics unavailable: {}", e.getMessage());
metrics = Collections.emptyMap(); // fallback
} else throw e;
}
Prevention
- Keep all cluster nodes on the same Cassandra version (no mixed versions while reading virtual tables).
- Pin monitoring code to the exact table column names (NAME_COL/VALUE_COL).
- Re-check the SELECT statement includes both required columns.
- Alert on this RuntimeException as a schema-drift signal, not transient failure.
When it happens
Trigger: Iterating rows returned by retrieveRows(getCountsMetricsStatement) where a row lacks the NAME_COL or VALUE_COL column — e.g. the underlying virtual table schema changed, an incomplete row was materialized into the result set, or a mixed-version cluster returns rows from an older table definition.
Common situations: Upgrading Cassandra where the virtual table definition changed between nodes; custom tooling that writes to or shadows the virtual table; internal schema drift making UntypedResultSet rows missing expected columns.
Related errors
- Invalid row " + row + " in table: " +…
- Can only unset '" + name + "'
- Cannot filter this table by partial partition key
- Cannot set bucket_sub_size to zero.
- Cannot update '" + name + "'
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/f58d6b95ed84b645.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/virtual/CIDRFilteringMetricsTable.java:219
}
public Map<String, Long> getCountsMetricsFromVtable()
{
String countsMetricsTableName = SchemaConstants.VIRTUAL_VIEWS + '.' +
CIDRFilteringMetricsTable.CIDRFilteringMetricsCountsTable.TABLE_NAME;
SelectStatement getCountsMetricsStatement =
(SelectStatement) QueryProcessor.getStatement(String.format("SELECT * FROM %s", countsMetricsTableName),
ClientState.forInternalCalls());
Map<String, Long> metrics = new HashMap<>();
UntypedResultSet result = retrieveRows(getCountsMetricsStatement);
for (UntypedResultSet.Row row : result)
{
if (!row.has(CIDRFilteringMetricsTable.CIDRFilteringMetricsCountsTable.NAME_COL) ||
!row.has(CIDRFilteringMetricsTable.CIDRFilteringMetricsCountsTable.VALUE_COL))
throw new RuntimeException("Invalid row " + row + " in table: " + countsMetricsTableName);
metrics.put(row.getString(CIDRFilteringMetricsTable.CIDRFilteringMetricsCountsTable.NAME_COL),
row.getLong(CIDRFilteringMetricsTable.CIDRFilteringMetricsCountsTable.VALUE_COL));
}
return metrics;
}
public Map<String, List<Double>> getLatenciesMetricsFromVtable()
{
String latenciesMetricsTableName = SchemaConstants.VIRTUAL_VIEWS + '.' +
CIDRFilteringMetricsTable.CIDRFilteringMetricsLatenciesTable.TABLE_NAME;
SelectStatement getLatenciesMetricsStatement =
(SelectStatement) QueryProcessor.getStatement(String.format("SELECT * FROM %s", latenciesMetricsTableName),
ClientState.forInternalCalls());
Map<String, List<Double>> metrics = new HashMap<>();View on GitHub (pinned to 88fd0f6a0e)