prestodb/presto · error · PrestoException
ICEBERG_TRANSACTION_CONFLICT_ERROR
ICEBERG_TRANSACTION_CONFLICT_ERROR
Error message
Not allowed to open write transactions on different tables
What it means
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.
Source
Thrown at presto-iceberg/src/main/java/com/facebook/presto/iceberg/transaction/IcebergTransactionContext.java:115
return Optional.empty();
}
public Optional<Table> initiallyReadTable(SchemaTableName tableName)
{
if (initiallyReadTables.containsKey(tableName)) {
return Optional.ofNullable(initiallyReadTables.get(tableName));
}
return Optional.empty();
}
public void registerTransaction(SchemaTableName tableName, Transaction transaction)
{
if (txByTable.isEmpty()) {
txByTable.put(tableName, transaction);
}
else if (!txByTable.containsKey(tableName)) {
throw new PrestoException(ICEBERG_TRANSACTION_CONFLICT_ERROR, "Not allowed to open write transactions on different tables");
}
}
public Table getIcebergTable(SchemaTableName schemaTableName, Function<SchemaTableName, Table> rawIcebergTableLoader)
{
Table table = getTransactionTable(schemaTableName)
.orElseGet(() -> initiallyReadTable(schemaTableName)
.orElseGet(() -> {
Table loadTable = rawIcebergTableLoader.apply(schemaTableName);
initiallyReadTables.computeIfAbsent(schemaTableName, ignored -> loadTable);
return loadTable;
}));
return new TransactionalTable(schemaTableName, table, opsFromTable(table));
}
public void registerCallback(Runnable callback)
{
checkArgument(this.callbacksOnCommit.get() == null, "Cannot set callbacksOnCommit multiple times");View on GitHub (pinned to 55bb57d202)
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)
Example fix
// before transactionContext.registerTransaction(tableA, tx); transactionContext.registerTransaction(tableB, tx); // throws // after transactionContext.registerTransaction(tableA, tx); // write to tableB in a separate transaction/statement
Defensive patterns
Strategy: try-catch
Validate before calling
if (transactionContext != null && !transactionContextIsEmptyOrContainsOnly(transactionContext, tableName)) {
throw new IllegalStateException("Cannot write to multiple tables in one transaction: " + tableName);
} Try / catch
try {
transactionContext.registerTransaction(tableName, transaction);
} catch (PrestoException e) {
if (e.getErrorCode().getName().equals("ICEBERG_TRANSACTION_CONFLICT_ERROR")) {
throw new IllegalStateException(
"Split the operation: only one Iceberg table may be written per transaction", e);
}
throw e;
} Prevention
- 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
When it happens
Trigger: Calling registerTransaction(tableNameA, tx) and then registerTransaction(tableNameB, tx) within the same Presto transaction where tableNameB != tableNameA.
Common situations: 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.
Related errors
- ICEBERG_TRANSACTION_CONFLICT_ERROR
- Not a Hive table:
- HIVE_TRANSACTION_NOT_FOUND
- TRANSACTION_CONFLICT
- dropping a table added/modified in the same transaction is n
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/0e54b014181b1d44.
Report an issue: GitHub.