apache/cassandra · error · UnknownTableException
Couldn't find table with id
Error message
Couldn't find table with id %s. If a table was just created, this is likely due to the schema not being fully propagated. Please wait for schema agreement on table creation.
What it means
SchemaProvider.getExistingTableMetadata resolves a table by TableId and throws UnknownTableException if no table with that UUID exists in the schema. The message warns that if the table was just created, schema may not have fully propagated, so the local node does not yet know the table id.
Solutions
- Wait for schema agreement (driver awaitSchemaAgreement or nodetool describecluster) before writing to newly created tables.
- Run nodetool resetlocalschema on nodes with persistently divergent schema.
- Verify the table id matches the current schema (system_schema.tables id) — if the table was dropped/recreated, use the new id.
- Retry the operation after propagation; it is usually transient during normal schema propagation.
Example fix
// before
session.execute("CREATE TABLE ks.t (id int PRIMARY KEY)");
session.execute("INSERT INTO ks.t (id) VALUES (1)"); // may hit UnknownTableException
// after
session.execute("CREATE TABLE ks.t (id int PRIMARY KEY)");
// wait for schema agreement before writing
cluster.getMetadata().checkSchemaAgreement();
session.execute("INSERT INTO ks.t (id) VALUES (1)"); Defensive patterns
Strategy: retry
Validate before calling
boolean schemaInAgreement(Session s) {
// all nodes report the same schema version; prefer driver checkSchemaAgreement()
return s.execute("SELECT schema_version FROM system.local").one() != null;
} Try / catch
catch (UnknownTableException e) {
logger.warn("Table id {} unknown locally — waiting for schema agreement", e.getTableId());
Thread.sleep(schemaAgreementWaitMs);
retryOperation();
} Prevention
- After CREATE TABLE, wait for schema agreement across the cluster before sending traffic.
- Monitor schema disagreement (nodetool describecluster) in multi-DC clusters.
- Run nodetool resetlocalschema on nodes stuck with divergent schema versions.
- Avoid drop-and-recreate table patterns that invalidate cached TableIds in clients and hints.
When it happens
Trigger: Routing a request by TableId (internal reads/writes, hints) to a node whose schema copy predates the table creation; getExistingTablePartitioner calling getExistingTableMetadata with a stale or unknown id; data arriving for a table dropped and recreated with a new id.
Common situations: Client writes immediately after CREATE TABLE before schema agreement; multi-DC clusters with slow schema propagation; inconsistent schema where a node missed the creation mutation; replayed hints/commitlog segments referencing old table ids.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Table with id does not exist
- ACCESS TO DATACENTERS operations not supported by…
- Aggregate ' ' already exists
- All indexed columns should be included into the column…
- ALREADY_EXISTS
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/3c155b8c0fe548e3.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/schema/SchemaProvider.java:193
}
@Nullable
default ColumnMetadata getColumnMetadata(String keyspace, String table, ByteBuffer name)
{
TableMetadata metadata = getTableMetadata(keyspace, table);
if (metadata == null) return null;
return metadata.getColumn(name);
}
default TableMetadata getExistingTableMetadata(TableId id) throws UnknownTableException
{
TableMetadata metadata = getTableMetadata(id);
if (metadata != null)
return metadata;
String message = "Couldn't find table with id " + id + ". If a table was just created, this is likely due to the schema "
+ "not being fully propagated. Please wait for schema agreement on table creation.";
throw new UnknownTableException(message, id);
}
/* Function helpers */
/**
* Get all function overloads with the specified name
*
* @param name fully qualified function name
* @return an empty list if the keyspace or the function name are not found;
* a non-empty collection of {@link Function} otherwise
*/
default Collection<UserFunction> getUserFunctions(FunctionName name)
{
if (!name.hasKeyspace())
throw new IllegalArgumentException(String.format("Function name must be fully qualified: got %s", name));
KeyspaceMetadata ksm = getKeyspaceMetadata(name.keyspace);
return ksm == nullView on GitHub (pinned to 88fd0f6a0e)