{"record":{"id":"02f198b8cd338979","repo":"prestodb/presto","slug":"transaction-conflict","errorCode":"TRANSACTION_CONFLICT","errorMessage":"Dropping and then recreating the same table in a transaction is not supported","messagePattern":"Dropping and then recreating the same table in a transaction is not supported","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/SemiTransactionalHiveMetastore.java","lineNumber":447,"sourceCode":"            PrincipalPrivileges principalPrivileges,\n            Optional<Path> currentPath,\n            boolean ignoreExisting,\n            PartitionStatistics statistics,\n            List<TableConstraint<String>> constraints)\n    {\n        setShared();\n        // When creating a table, it should never have partition actions. This is just a sanity check.\n        checkNoPartitionAction(table.getDatabaseName(), table.getTableName());\n        Action<TableAndMore> oldTableAction = tableActions.get(table.getSchemaTableName());\n        TableAndMore tableAndMore = new TableAndMore(table, Optional.of(principalPrivileges), currentPath, Optional.empty(), ignoreExisting, statistics, statistics, constraints);\n        if (oldTableAction == null) {\n            HdfsContext context = new HdfsContext(session, table.getDatabaseName(), table.getTableName(), table.getStorage().getLocation(), true);\n            tableActions.put(table.getSchemaTableName(), new Action<>(ActionType.ADD, tableAndMore, context));\n            return;\n        }\n        switch (oldTableAction.getType()) {\n            case DROP:\n                throw new PrestoException(TRANSACTION_CONFLICT, \"Dropping and then recreating the same table in a transaction is not supported\");\n            case ADD:\n            case ALTER:\n            case INSERT_EXISTING:\n                throw new TableAlreadyExistsException(table.getSchemaTableName());\n            default:\n                throw new IllegalStateException(\"Unknown action type\");\n        }\n    }\n\n    public synchronized void dropTable(HdfsContext context, String databaseName, String tableName)\n    {\n        setShared();\n        // Dropping table with partition actions requires cleaning up staging data, which is not implemented yet.\n        checkNoPartitionAction(databaseName, tableName);\n        SchemaTableName schemaTableName = new SchemaTableName(databaseName, tableName);\n        Action<TableAndMore> oldTableAction = tableActions.get(schemaTableName);\n        if (oldTableAction == null || oldTableAction.getType() == ActionType.ALTER) {\n            tableActions.put(schemaTableName, new Action<>(ActionType.DROP, null, context));","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/SemiTransactionalHiveMetastore.java#L429-L465","documentation":"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.","triggerScenarios":"Calling dropTable followed by createTable for the same SchemaTableName within the same transaction (same SemiTransactionalHiveMetastore instance before commit).","commonSituations":"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.","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"],"exampleFix":"// before\nmetastore.dropTable(ctx, db, tbl, false);\nmetastore.createTable(ctx, table, privileges);\n// after\nmetastore.dropTable(ctx, db, tbl, false);\nmetastore.commit();\nSemiTransactionalHiveMetastore m2 = ...; // new transaction\nm2.createTable(ctx, table, privileges);","handlingStrategy":"try-catch","validationCode":"// track per-transaction table actions in app code\nSet<SchemaTableName> dropped = ...;\nif (dropped.contains(new SchemaTableName(db, tbl))) {\n    throw new IllegalStateException(\"Commit drop before recreating \" + db + \".\" + tbl);\n}","typeGuard":null,"tryCatchPattern":"try {\n    metastore.createTable(ctx, table, privileges);\n} catch (PrestoException e) {\n    if (e.getErrorCode() == TRANSACTION_CONFLICT.toErrorCode()) {\n        metastore.commit(); // commit the drop\n        metastore = newTransaction();\n        metastore.createTable(ctx, table, privileges);\n    } else throw e;\n}","preventionTips":["Never drop and recreate the same table in one transaction","Commit between drop and create","Prefer replacing table contents (insert/alter) over drop+create"],"tags":["hive","transaction","conflict","drop-create"],"backgroundTag":"transaction-conflict","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}