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
- Split into two transactions: commit the DROP first, then run the CREATE in a new transaction
- Use replaceTable/alterTable-style flows instead of drop+create when possible
- 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
- Never drop and recreate the same table in one transaction
- Commit between drop and create
- Prefer replacing table contents (insert/alter) over drop+create
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
- HIVE_TRANSACTION_NOT_FOUND
- HIVE_CONCURRENT_MODIFICATION_DETECTED
- dropping a table added/modified in the same transaction is n
- Inserting into an unpartitioned table that were added, alter
- ACCUMULO_TABLE_EXISTS
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/02f198b8cd338979.
Report an issue: GitHub.