prestodb/presto · error · PrestoException

TRANSACTION_CONFLICT

TRANSACTION_CONFLICT

Error message

Dropping and then recreating the same table in a transaction is not supported

What it means

Within one transaction, SemiTransactionalHiveMetastore records the first action on a table. If the existing action is DROP and createTable is then called for the same table, the metastore cannot represent the drop+recreate sequence and throws PrestoException with code TRANSACTION_CONFLICT. This prevents ambiguous commit-time behavior.

Source

Thrown at presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/SemiTransactionalHiveMetastore.java:447

            PrincipalPrivileges principalPrivileges,
            Optional<Path> currentPath,
            boolean ignoreExisting,
            PartitionStatistics statistics,
            List<TableConstraint<String>> constraints)
    {
        setShared();
        // When creating a table, it should never have partition actions. This is just a sanity check.
        checkNoPartitionAction(table.getDatabaseName(), table.getTableName());
        Action<TableAndMore> oldTableAction = tableActions.get(table.getSchemaTableName());
        TableAndMore tableAndMore = new TableAndMore(table, Optional.of(principalPrivileges), currentPath, Optional.empty(), ignoreExisting, statistics, statistics, constraints);
        if (oldTableAction == null) {
            HdfsContext context = new HdfsContext(session, table.getDatabaseName(), table.getTableName(), table.getStorage().getLocation(), true);
            tableActions.put(table.getSchemaTableName(), new Action<>(ActionType.ADD, tableAndMore, context));
            return;
        }
        switch (oldTableAction.getType()) {
            case DROP:
                throw new PrestoException(TRANSACTION_CONFLICT, "Dropping and then recreating the same table in a transaction is not supported");
            case ADD:
            case ALTER:
            case INSERT_EXISTING:
                throw new TableAlreadyExistsException(table.getSchemaTableName());
            default:
                throw new IllegalStateException("Unknown action type");
        }
    }

    public synchronized void dropTable(HdfsContext context, String databaseName, String tableName)
    {
        setShared();
        // Dropping table with partition actions requires cleaning up staging data, which is not implemented yet.
        checkNoPartitionAction(databaseName, tableName);
        SchemaTableName schemaTableName = new SchemaTableName(databaseName, tableName);
        Action<TableAndMore> oldTableAction = tableActions.get(schemaTableName);
        if (oldTableAction == null || oldTableAction.getType() == ActionType.ALTER) {
            tableActions.put(schemaTableName, new Action<>(ActionType.DROP, null, context));

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Split into two transactions: commit the DROP first, then run the CREATE in a new transaction
  2. Use replaceTable/alterTable-style flows instead of drop+create when possible
  3. Restructure the job so table recreation happens outside the transactional session

Example fix

// before
metastore.dropTable(ctx, db, tbl, false);
metastore.createTable(ctx, table, privileges);
// after
metastore.dropTable(ctx, db, tbl, false);
metastore.commit();
SemiTransactionalHiveMetastore m2 = ...; // new transaction
m2.createTable(ctx, table, privileges);
Defensive patterns

Strategy: try-catch

Validate before calling

// track per-transaction table actions in app code
Set<SchemaTableName> dropped = ...;
if (dropped.contains(new SchemaTableName(db, tbl))) {
    throw new IllegalStateException("Commit drop before recreating " + db + "." + tbl);
}

Try / catch

try {
    metastore.createTable(ctx, table, privileges);
} catch (PrestoException e) {
    if (e.getErrorCode() == TRANSACTION_CONFLICT.toErrorCode()) {
        metastore.commit(); // commit the drop
        metastore = newTransaction();
        metastore.createTable(ctx, table, privileges);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling dropTable followed by createTable for the same SchemaTableName within the same transaction (same SemiTransactionalHiveMetastore instance before commit).

Common situations: Schema-migration scripts doing DROP TABLE then CREATE TABLE in one session/transaction; test setups resetting a table inside one transaction; idempotent ingestion jobs that recreate target tables.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/02f198b8cd338979. Report an issue: GitHub.