prestodb/presto · error · SemanticException
INVALID_TRANSACTION_MODE
INVALID_TRANSACTION_MODE
Error message
Multiple transaction isolation levels specified
What it means
Validation inside extractIsolationLevel, which scans the characteristics of a START TRANSACTION statement: more than one ISOLATION LEVEL clause was supplied (e.g. 'START TRANSACTION ISOLATION LEVEL READ COMMITTED, ISOLATION LEVEL SERIALIZABLE'), so the isolation level is ambiguous.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/execution/StartTransactionTask.java:79
isolationLevel.orElse(TransactionManager.DEFAULT_ISOLATION),
readOnly.orElse(TransactionManager.DEFAULT_READ_ONLY),
false);
stateMachine.setStartedTransactionId(transactionId);
// Since the current session does not contain this new transaction ID, we need to manually mark it as inactive
// when this statement completes.
transactionManager.trySetInactive(transactionId);
return immediateFuture(null);
}
private static Optional<IsolationLevel> extractIsolationLevel(StartTransaction startTransaction)
{
if (startTransaction.getTransactionModes().stream()
.filter(Isolation.class::isInstance)
.count() > 1) {
throw new SemanticException(INVALID_TRANSACTION_MODE, startTransaction, "Multiple transaction isolation levels specified");
}
return startTransaction.getTransactionModes().stream()
.filter(Isolation.class::isInstance)
.map(Isolation.class::cast)
.map(Isolation::getLevel)
.map(StartTransactionTask::convertLevel)
.findFirst();
}
private static Optional<Boolean> extractReadOnly(StartTransaction startTransaction)
{
if (startTransaction.getTransactionModes().stream()
.filter(TransactionAccessMode.class::isInstance)
.count() > 1) {
throw new SemanticException(INVALID_TRANSACTION_MODE, startTransaction, "Multiple transaction read modes specified");
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Keep a single ISOLATION LEVEL clause in START TRANSACTION.
- Fix the SQL builder/template so transaction modes are not concatenated twice.
- Validate the statement text before execution in generated-SQL pipelines.
Example fix
-- before START TRANSACTION ISOLATION LEVEL READ COMMITTED, ISOLATION LEVEL SERIALIZABLE; -- after START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Defensive patterns
Strategy: validation
Validate before calling
// count isolation clauses before execution int n = countMatches(sql, "ISOLATION LEVEL"); if (n > 1) reject(sql);
Try / catch
// catch SemanticException with code INVALID_TRANSACTION_MODE and message 'Multiple transaction isolation levels specified'; fix SQL and re-run
Prevention
- Emit each transaction mode at most once in SQL generators
- Unit-test generated START TRANSACTION statements
- Deduplicate transaction-mode tokens when composing SQL
When it happens
Trigger: START TRANSACTION containing two or more Isolation transaction modes, e.g. START TRANSACTION ISOLATION LEVEL READ COMMITTED, ISOLATION LEVEL SERIALIZABLE — extractIsolationLevel() counts >1 Isolation instances.
Common situations: Duplicated clauses from query generation bugs, templated SQL concatenating transaction-mode fragments, copy-paste mistakes in scripts.
Related errors
- Invalid value [%s]. Valid values: %s
- CLICKHOUSE_QUERY_GENERATOR_FAILURE
- Invalid token URI:
- Invalid offset minutes %s
- DRUID_QUERY_GENERATOR_FAILURE
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/730af75f89ad8ae5.
Report an issue: GitHub.