apache/cassandra · error · RuntimeException
Invalid row " + row + " in table: " +…
Error message
Invalid row " + row + " in table: " + latenciesMetricsTableName
What it means
getLatenciesMetricsFromVtable reads percentile latency rows from the CIDRFilteringMetrics latencies virtual table. Every row must contain the metric name and the P50 column (percentile family P95/P99/P999/P999_MAX is read afterwards); a row missing NAME_COL or P50_COL cannot be parsed, so a RuntimeException flags it.
Solutions
- Ensure all nodes are on the same Cassandra version so the latencies virtual table emits all percentile columns.
- Confirm the SELECT statement projects the full column set (name + p50/p95/p99/p999/p999_max).
- Re-execute the query against a specific healthy node.
- Treat persistent occurrences as an internal bug and report with the offending row's column list.
Defensive patterns
Strategy: try-catch
Validate before calling
for (UntypedResultSet.Row row : result)
if (!row.has("name") || !row.has("p50"))
throw new IllegalStateException("CIDR latencies table schema mismatch; check node versions");
Try / catch
try {
latencies = getLatenciesMetricsFromVtable();
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Invalid row")) {
logger.warn("CIDR latency metrics unavailable: {}", e.getMessage());
latencies = Collections.emptyMap(); // fallback
} else throw e;
}
Prevention
- Ensure the SELECT projects name and all percentile columns (p50, p95, p99, p999, p999_max).
- Avoid reading virtual metrics tables during rolling upgrades / mixed-version windows.
- Match monitoring tooling to the exact Cassandra version's virtual table schema.
- Treat missing-column rows as version-skew indicators and gate reads on cluster schema agreement.
When it happens
Trigger: The prepared getLatenciesMetricsStatement returns rows lacking the name or P50 columns — typically because the latencies virtual table schema on some node differs (version skew, partially applied change) or the SELECT was altered to fetch fewer columns.
Common situations: Mixed-version clusters during rolling upgrade where percentile column set changed; customized monitoring scripts replacing the built-in statement; reading the table from a node whose virtual-table implementation is older.
Related errors
- Invalid row " + row + " in table: " + countsMetricsTableName
- 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/7520118139077cb5.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/virtual/CIDRFilteringMetricsTable.java:244
}
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<>();
UntypedResultSet result = retrieveRows(getLatenciesMetricsStatement);
for (UntypedResultSet.Row row : result)
{
if (!row.has(CIDRFilteringMetricsLatenciesTable.NAME_COL) ||
!row.has(CIDRFilteringMetricsLatenciesTable.P50_COL))
throw new RuntimeException("Invalid row " + row + " in table: " + latenciesMetricsTableName);
metrics.put(row.getString(CIDRFilteringMetricsTable.CIDRFilteringMetricsLatenciesTable.NAME_COL),
Arrays.asList(row.getDouble(CIDRFilteringMetricsLatenciesTable.P50_COL),
row.getDouble(CIDRFilteringMetricsLatenciesTable.P95_COL),
row.getDouble(CIDRFilteringMetricsLatenciesTable.P99_COL),
row.getDouble(CIDRFilteringMetricsLatenciesTable.P999_COL),
row.getDouble(CIDRFilteringMetricsLatenciesTable.MAX_COL)));
}
return metrics;
}
}
View on GitHub (pinned to 88fd0f6a0e)