t8y2/dbx · error · SQLException
A manual transaction is already active
Error message
A manual transaction is already active
What it means
beginManualTransaction enforces a single active manual transaction via the static manualTransactionActive flag. If begin is called while a previous manual transaction was begun but not committed/rolled back, it throws this SQLException instead of nesting or silently reusing the existing transaction.
Source
Thrown at plugins/jdbc/src/main/java/app/dbx/jdbc/DbxJdbcPlugin.java:1044
}
rows.add(row);
}
}
}
result.set("columns", columns);
result.set("rows", rows);
result.put("affected_rows", columns.isEmpty() ? Math.max(executed.updateCount(), 0) : 0);
result.put("execution_time_ms", (System.nanoTime() - start) / 1_000_000);
result.put("truncated", truncated);
return result;
}
}
private static ObjectNode beginManualTransaction(JsonNode connection, String database, String schema)
throws SQLException {
if (manualTransactionActive) {
throw new SQLException("A manual transaction is already active");
}
Connection conn = openConnection(connection);
DatabaseMetaData metadata = readMetadata(conn::getMetaData);
Boolean supportsTransactions = metadata == null ? null : readMetadata(metadata::supportsTransactions);
if (Boolean.FALSE.equals(supportsTransactions)) {
throw new SQLFeatureNotSupportedException("This JDBC driver does not support transactions");
}
applyExecutionContext(connection, conn, database, schema);
conn.setAutoCommit(false);
manualTransactionActive = true;
return okResult();
}
private static JsonNode executeInManualTransaction(
JsonNode connection,
String sql,
String database,
String schema,View on GitHub (pinned to c0390bff16)
Solutions
- Commit or roll back the active manual transaction before starting a new one.
- Wrap transactional work in try/finally so commit/rollback always runs, resetting the flag even on failure.
- Check for an earlier operation that failed mid-transaction and left manualTransactionActive true; restart the session/plugin if stuck.
- Serialize transaction usage — the plugin's transaction state is process-wide static, so avoid concurrent manual transactions.
Example fix
// before
beginTx(conn);
runStatements(); // throws, no rollback
beginTx(conn); // -> "A manual transaction is already active"
// after
beginTx(conn);
try {
runStatements();
commitTx(conn);
} catch (Exception e) {
rollbackTx(conn);
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
plugin.beginManualTransaction(connCfg);
// ... statements ...
plugin.commit();
} catch (java.sql.SQLException e) {
if (e.getMessage().contains("already active")) {
plugin.rollback(); // clear the stuck transaction
throw new IllegalStateException("Previous manual transaction was not finalized", e);
}
throw e;
} Prevention
- Always pair begin with commit/rollback in try/finally
- Treat any exception inside a transaction as requiring rollback before retry
- Never run concurrent manual transactions — the flag is process-wide static
- Restart the plugin/session if you suspect the flag is stuck after a crash
When it happens
Trigger: Calling the begin-transaction operation twice without an intervening commit or rollback on the same plugin instance — e.g. an earlier script path errored between begin and commit, or concurrent requests both hit beginManualTransaction.
Common situations: Exception in the middle of a manual transaction leaving the flag set, forgetting to call commit/rollback in an error handler, or two threads/tasks sharing the plugin's static state and racing on begin.
Related errors
- Transactions are not supported by this JDBC driver
- This JDBC driver does not support transactions
- No manual transaction is active
- The manual transaction belongs to a different JDBC connectio
- JDBC pool registry must be attached before connecting
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/8d8aebe3aba5112f.
Report an issue: GitHub.