{"record":{"id":"0e54b014181b1d44","repo":"prestodb/presto","slug":"iceberg-transaction-conflict-error-0e54b0","errorCode":"ICEBERG_TRANSACTION_CONFLICT_ERROR","errorMessage":"Not allowed to open write transactions on different tables","messagePattern":"Not allowed to open write transactions on different tables","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-iceberg/src/main/java/com/facebook/presto/iceberg/transaction/IcebergTransactionContext.java","lineNumber":115,"sourceCode":"        return Optional.empty();\n    }\n\n    public Optional<Table> initiallyReadTable(SchemaTableName tableName)\n    {\n        if (initiallyReadTables.containsKey(tableName)) {\n            return Optional.ofNullable(initiallyReadTables.get(tableName));\n        }\n\n        return Optional.empty();\n    }\n\n    public void registerTransaction(SchemaTableName tableName, Transaction transaction)\n    {\n        if (txByTable.isEmpty()) {\n            txByTable.put(tableName, transaction);\n        }\n        else if (!txByTable.containsKey(tableName)) {\n            throw new PrestoException(ICEBERG_TRANSACTION_CONFLICT_ERROR, \"Not allowed to open write transactions on different tables\");\n        }\n    }\n\n    public Table getIcebergTable(SchemaTableName schemaTableName, Function<SchemaTableName, Table> rawIcebergTableLoader)\n    {\n        Table table = getTransactionTable(schemaTableName)\n                .orElseGet(() -> initiallyReadTable(schemaTableName)\n                        .orElseGet(() -> {\n                            Table loadTable = rawIcebergTableLoader.apply(schemaTableName);\n                            initiallyReadTables.computeIfAbsent(schemaTableName, ignored -> loadTable);\n                            return loadTable;\n                        }));\n        return new TransactionalTable(schemaTableName, table, opsFromTable(table));\n    }\n\n    public void registerCallback(Runnable callback)\n    {\n        checkArgument(this.callbacksOnCommit.get() == null, \"Cannot set callbacksOnCommit multiple times\");","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-iceberg/src/main/java/com/facebook/presto/iceberg/transaction/IcebergTransactionContext.java#L97-L133","documentation":"IcebergTransactionContext tracks at most one write transaction per coordinator transaction, keyed by table name. registerTransaction allows re-registering for the same table, but if transactions already exist for a different table it throws PrestoException(ICEBERG_TRANSACTION_CONFLICT_ERROR) because multi-table writes are not supported in one transaction.","triggerScenarios":"Calling registerTransaction(tableNameA, tx) and then registerTransaction(tableNameB, tx) within the same Presto transaction where tableNameB != tableNameA.","commonSituations":"A single INSERT/MERGE statement or session touching two Iceberg tables in write mode; a connector bug or plugin attempting cross-table writes in one transaction; queries combining writes to multiple catalogs/tables that map into the same transaction context.","solutions":["Restructure the operation so each Presto transaction writes to a single Iceberg table (split into separate statements/transactions)","If a custom connector/plugin, ensure each table write acquires its own transaction context","Check for accidental aliasing where two different SchemaTableNames refer to what should be one table (case/catalog mismatch)"],"exampleFix":"// before\ntransactionContext.registerTransaction(tableA, tx);\ntransactionContext.registerTransaction(tableB, tx); // throws\n// after\ntransactionContext.registerTransaction(tableA, tx);\n// write to tableB in a separate transaction/statement","handlingStrategy":"try-catch","validationCode":"if (transactionContext != null && !transactionContextIsEmptyOrContainsOnly(transactionContext, tableName)) {\n    throw new IllegalStateException(\"Cannot write to multiple tables in one transaction: \" + tableName);\n}","typeGuard":null,"tryCatchPattern":"try {\n    transactionContext.registerTransaction(tableName, transaction);\n} catch (PrestoException e) {\n    if (e.getErrorCode().getName().equals(\"ICEBERG_TRANSACTION_CONFLICT_ERROR\")) {\n        throw new IllegalStateException(\n            \"Split the operation: only one Iceberg table may be written per transaction\", e);\n    }\n    throw e;\n}","preventionTips":["Design writes so each transaction targets exactly one Iceberg table","Avoid multi-table INSERT/MERGE patterns against Iceberg in a single statement/session","Verify SchemaTableName construction (catalog/schema/table casing) to avoid false conflicts"],"tags":["iceberg","transaction"],"backgroundTag":"multi-table-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"}