prestodb/presto · error · PrestoException
MULTI_CATALOG_WRITE_CONFLICT
MULTI_CATALOG_WRITE_CONFLICT
Error message
Multi-catalog writes not supported in a single transaction. Attempt write to catalog %s, but already wrote to catalog %s
What it means
Thrown by TransactionMetadata.checkConnectorWrite when a single transaction attempts to write through two different connectors. Presto does not support multi-catalog (cross-connector) writes in one transaction: writtenConnectorId uses compareAndSet to record the first writing catalog, and any subsequent write to a different catalog fails.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/transaction/InMemoryTransactionManager.java:589
{
if (connector instanceof InternalConnector) {
return ((InternalConnector) connector).beginTransaction(transactionId, isolationLevel, readOnly);
}
else {
return connector.beginTransaction(isolationLevel, autoCommitContext, readOnly);
}
}
public synchronized void checkConnectorWrite(ConnectorId connectorId)
{
checkOpenTransaction();
ConnectorTransactionMetadata transactionMetadata = connectorIdToMetadata.get(connectorId);
checkArgument(transactionMetadata != null, "Cannot record write for connector not part of transaction");
if (readOnly) {
throw new PrestoException(READ_ONLY_VIOLATION, "Cannot execute write in a read-only transaction");
}
if (!writtenConnectorId.compareAndSet(null, connectorId) && !writtenConnectorId.get().equals(connectorId)) {
throw new PrestoException(
MULTI_CATALOG_WRITE_CONFLICT,
format(
"Multi-catalog writes not supported in a single transaction. Attempt write to catalog %s, but already wrote to catalog %s",
connectorId,
writtenConnectorId.get()));
}
if (transactionMetadata.isSingleStatementWritesOnly() && !autoCommitContext) {
throw new PrestoException(AUTOCOMMIT_WRITE_CONFLICT, "Catalog " + connectorId + " only supports writes using autocommit");
}
}
public synchronized ListenableFuture<?> asyncCommit()
{
if (!completedSuccessfully.compareAndSet(null, true)) {
if (completedSuccessfully.get()) {
// Already done
return immediateFuture(null);
}View on GitHub (pinned to 55bb57d202)
Solutions
- Split the work into separate transactions, one per catalog.
- Restrict the transaction's writes to a single catalog.
- Use non-transactional (autocommit) execution for the extra-catalog writes.
- Redesign the pipeline (e.g. stage data externally) since Presto cannot atomically commit across catalogs.
Example fix
// before START TRANSACTION; INSERT INTO hive.t SELECT * FROM src; INSERT INTO mysql.t SELECT * FROM src; COMMIT; // after: separate transactions per catalog START TRANSACTION; INSERT INTO hive.t SELECT * FROM src; COMMIT; START TRANSACTION; INSERT INTO mysql.t SELECT * FROM src; COMMIT;
Defensive patterns
Strategy: validation
Validate before calling
// Track which catalogs already received writes in this transaction
Set<ConnectorId> written = new HashSet<>();
written.add(firstConnectorId);
if (!written.contains(targetConnectorId)) {
// would trigger MULTI_CATALOG_WRITE_CONFLICT — commit first, start new transaction
} Type guard
boolean isSameCatalog(ConnectorId writtenConnectorId, ConnectorId next) {
return writtenConnectorId == null || writtenConnectorId.equals(next);
} Try / catch
try {
transactionMetadata.checkConnectorWrite(connectorId);
} catch (PrestoException e) {
if (e.getErrorCode().getCode() == StandardErrorCode.MULTI_CATALOG_WRITE_CONFLICT.toErrorCode().getCode()) {
// split: finish current transaction, open a new one for this catalog
transactionManager.asyncCommit(txId);
txId = transactionManager.beginTransaction(false);
} else {
throw e;
}
} Prevention
- Design workloads so each transaction writes to exactly one catalog.
- Split cross-catalog pipelines into sequential transactions.
- Document which connectors your transaction touches before writing.
- Prefer autocommit for the second catalog's writes.
When it happens
Trigger: Two statements in the same transaction write to catalogs with different ConnectorIds, so the second checkConnectorWrite finds writtenConnectorId already set to another catalog and the CAS fails.
Common situations: Query writing to two different catalogs (e.g. INSERT into hive then INSERT into mysql) inside one explicit transaction; a federated query with side-effects on multiple connectors; plugin-generated writes to a second catalog.
Related errors
- TRANSACTION_ALREADY_ABORTED
- READ_ONLY_VIOLATION
- AUTOCOMMIT_WRITE_CONFLICT
- INVALID_TABLE_PROPERTY
- ACCUMULO_TABLE_EXISTS
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/fe6b057ee3aa6afb.
Report an issue: GitHub.