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

  1. Check existing constraints (SHOW CREATE TABLE) before adding; skip if the same constraint already exists.
  2. Make migrations idempotent by catching TableConstraintAlreadyExistsException and treating it as success.
  3. Use unique, descriptive constraint names to avoid collisions.
  4. 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

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.