prestodb/presto · error · TableConstraintAlreadyExistsException
Constraint already exists
Error message
Constraint already exists
What it means
When the metastore's addConstraint RPC raises AlreadyExistsException, ThriftHiveMetastore throws TableConstraintAlreadyExistsException ('Constraint already exists') with the constraint name. The constraint you are adding is already present on the table.
Source
Thrown at presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftHiveMetastore.java:1763
callableName = "addNotNullConstraint";
apiStats = stats.getAddNotNullConstraint();
callableClient = apiStats.wrap(() ->
getMetastoreClientThenCall(metastoreContext, client -> {
client.addNotNullConstraint(notNullConstraint);
return null;
}));
}
else {
throw new PrestoException(NOT_SUPPORTED, "This connector can only handle Unique/Primary Key/Not Null constraints at this time");
}
try {
retry()
.stopOnIllegalExceptions()
.run(callableName, callableClient);
}
catch (AlreadyExistsException e) {
throw new TableConstraintAlreadyExistsException(tableConstraint.getName());
}
catch (TException e) {
throw new PrestoException(HIVE_METASTORE_ERROR, e);
}
catch (Exception e) {
throw propagate(e);
}
return EMPTY_RESULT;
}
@Override
public long lock(MetastoreContext metastoreContext, String databaseName, String tableName)
{
try {
final LockComponent lockComponent = new LockComponent(EXCLUSIVE, LockLevel.TABLE, databaseName);
lockComponent.setTablename(tableName);
final LockRequest lockRequest = new LockRequest(Lists.newArrayList(lockComponent),View on GitHub (pinned to 55bb57d202)
Solutions
- Check existing constraints (SHOW CREATE TABLE) before adding; skip if the same constraint already exists.
- Make migrations idempotent by catching TableConstraintAlreadyExistsException and treating it as success.
- Use unique, descriptive constraint names to avoid collisions.
- If the existing constraint differs from what you want, drop it first then re-add.
Example fix
// before
metastore.addConstraint(context, db, table, constraint);
// after: idempotent
try {
metastore.addConstraint(context, db, table, constraint);
} catch (TableConstraintAlreadyExistsException e) {
// constraint already present; ignore
} Defensive patterns
Strategy: try-catch
Validate before calling
// inspect existing constraints before adding // e.g. via table metadata: existingNames = tableConstraints.stream().map(TableConstraint::getName).collect(toSet()); if (existingNames.contains(constraint.getName())) return; // already present
Try / catch
try {
metastore.addConstraint(context, db, table, constraint);
} catch (TableConstraintAlreadyExistsException e) {
// idempotent: already added, treat as success
} Prevention
- Make constraint migrations idempotent (check-then-add or catch-already-exists).
- Use unique, deterministic constraint names.
- Guard against concurrent DDL from multiple sessions on the same table.
When it happens
Trigger: Calling addConstraint with a constraint whose name collides with an existing constraint on the table, or re-running a migration that already added the primary key/unique/not-null constraint.
Common situations: Non-idempotent migration scripts run twice, default constraint names colliding across retry attempts, constraint added concurrently by another session, replaying DDL after a partial failure where the first attempt actually succeeded.
Related errors
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/220374d20f4b8261.
Report an issue: GitHub.