apache/shardingsphere · error · InvalidTransactionHandleException
Invalid transaction handle: %d
Error message
Invalid transaction handle: %d
What it means
InvalidTransactionHandleException thrown by FirebirdCommitTransactionCommandExecutor.validateTransactionHandle when the transaction handle in a COMMIT packet is not registered as active for the connection in FirebirdTransactionIdGenerator. The proxy tracks per-connection transaction handles; committing an unknown or already-closed handle is rejected.
Source
Thrown at proxy/frontend/dialect/firebird/src/main/java/org/apache/shardingsphere/proxy/frontend/firebird/command/query/transaction/FirebirdCommitTransactionCommandExecutor.java:58
private final ConnectionSession connectionSession;
@Override
public Collection<DatabasePacket> execute() throws SQLException {
int transactionHandle = packet.getTransactionId();
validateTransactionHandle(transactionHandle);
if (!connectionSession.isAutoCommit()) {
ProxyBackendTransactionManager transactionManager = new ProxyBackendTransactionManager(connectionSession.getDatabaseConnectionManager());
// TODO add rollback and return exception
transactionManager.commit();
}
FirebirdTransactionIdGenerator.getInstance().closeTransaction(connectionSession.getConnectionId(), transactionHandle);
return Collections.singleton(new FirebirdGenericResponsePacket());
}
private void validateTransactionHandle(final int transactionHandle) {
if (!FirebirdTransactionIdGenerator.getInstance().isTransactionActive(connectionSession.getConnectionId(), transactionHandle)) {
throw new InvalidTransactionHandleException(transactionHandle);
}
}
}
View on GitHub (pinned to e952770a21)
Solutions
- Commit each transaction handle exactly once; after commit or rollback, discard the handle and start a new transaction.
- On ambiguous timeout errors, do not blind-retry COMMIT; check transaction state (or reconnect) first, since the handle is closed by a successful commit.
- Keep transaction start/commit on the same connection/attachment.
Defensive patterns
Strategy: validation
Validate before calling
Set<Long> activeTx = new HashSet<>();
if (!activeTx.contains(trHandle)) throw new IllegalStateException("transaction not active");
sendCommit(trHandle);
activeTx.remove(trHandle); Try / catch
catch (SQLException e) {
if (e.getMessage().contains("Invalid transaction handle")) {
// handle already committed/closed elsewhere: treat as success only if state confirms it
verifyTransactionClosed(); startNewTransaction();
} else throw e;
} Prevention
- Commit each handle exactly once and remove it from client state afterwards.
- Never blind-retry COMMIT after a timeout; verify state first.
- Do not carry transaction handles across reconnects.
When it happens
Trigger: execute() calls isTransactionActive(connectionSession.getConnectionId(), transactionHandle) before committing; false when the handle was never opened by a START TRANSACTION, was already committed/rolled back, or belongs to a different connection.
Common situations: double COMMIT (client retries after timeout, first commit succeeded); handle reuse after rollback; two-phase or pooled clients carrying transaction handles across reconnects; client sending COMMIT for a transaction started on another attachment.
Related errors
- Can not locate agent jar file by URL `%s`.
- Can not find field name `%s` in class %s.
- Invalid statement handle: %d
- Batch already opened for statement handle %d
- Invalid batch handle: statement handle %d
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/a8ff0e1ba341747d.
Report an issue: GitHub.