apache/druid · error · DuplicateKeyException
Tried to insert a duplicate table: %s
Error message
Tried to insert a duplicate table: %s
What it means
When inserting a new catalog table into the DB, the INSERT hits a unique-constraint violation (DuplicateKeyException path after DbUtils.isDuplicateRecordException). The manager maps the raw JDBC error to this DuplicateKeyException naming the table, because a table with the same name already exists.
Source
Thrown at extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/storage/sql/SQLCatalogManager.java:167
{
final TableSpec spec = table.spec();
final long updateTime = System.currentTimeMillis();
final Update stmt = handle
.createStatement(statement(INSERT_TABLE))
.bind(SCHEMA_NAME_COL, table.id().schema())
.bind(TABLE_NAME_COL, table.id().name())
.bind(CREATION_TIME_COL, updateTime)
.bind(UPDATE_TIME_COL, updateTime)
.bind(STATE_COL, TableMetadata.TableState.ACTIVE.code())
.bind(TABLE_TYPE_COL, spec.type())
.bind(PROPERTIES_COL, JacksonUtils.toBytes(jsonMapper, spec.properties()))
.bind(COLUMNS_COL, JacksonUtils.toBytes(jsonMapper, spec.columns()));
try {
stmt.execute();
}
catch (UnableToExecuteStatementException e) {
if (DbUtils.isDuplicateRecordException(e)) {
throw new DuplicateKeyException(
"Tried to insert a duplicate table: %s",
table.sqlName()
);
} else {
throw e;
}
}
sendAddition(table, updateTime);
return updateTime;
}
}
);
}
catch (CallbackFailedException e) {
if (e.getCause() instanceof DuplicateKeyException) {
throw (DuplicateKeyException) e.getCause();
}
throw e;View on GitHub (pinned to 9b90983fd2)
Solutions
- Check existence first with the manager's readTable/exists API before calling createTable, or catch DuplicateKeyException and treat it as 'already created'.
- Use the table lock (createTable under lock when available) so concurrent creators serialize.
- If a retry caused it, switch create retry logic to idempotent upsert (alterTable/createTable-if-absent semantics).
- Inspect the DB directly (SELECT from the catalog table table) to confirm the existing row and decide whether to reuse or delete it.
Example fix
// before
manager.createTable(id, spec); // throws DuplicateKeyException if it exists
// after
if (manager.readTable(id) == null) {
manager.createTable(id, spec);
} Defensive patterns
Strategy: try-catch
Validate before calling
if (manager.readTable(id) != null) {
throw new IllegalStateException("Table already exists: " + id.sqlName());
} Try / catch
try {
manager.createTable(id, spec);
} catch (DuplicateKeyException e) {
// treat as already-created; fall back to readTable
existing = manager.readTable(id);
} Prevention
- Check existence before create; make create logic idempotent.
- Route all table creation through the manager's locking to serialize writers.
- Avoid blind retries of create calls without checking prior success.
When it happens
Trigger: Calling SQLCatalogManager.createTable (through its JDBI withHandle callback) with a TableId whose sqlName already has a row in the catalog table definition table, causing the INSERT to violate the primary/unique key.
Common situations: Client-side create raced with another process creating the same table without a lock or prior exists() check; retry logic re-running a create that already succeeded; concurrent tooling or automation double-registering a table.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Cannot translate sqlTypeName[%s] to Druid type for field[%s]
- Invalid parameter type:
- Unsupported query result format:
- Cannot translate sqlTypeName[%s] to Druid type for field[%s]
- requires a ThetaSketch as the argument
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/a19faf1cbfafa6ff.
Report an issue: GitHub.