NationalSecurityAgency/ghidra · error · RuntimeException
Transaction already started
Error message
Transaction already started
What it means
Thrown by State.requireNoTx() when a command that must run outside a transaction is invoked while a trace transaction is still open (tx != null). Ghidra's JDI trace bridge tracks a single active RmiTransaction in the State object; operations like opening a new transaction or connecting require there be none in flight. The guard prevents nested/overlapping transactions that would corrupt trace snapshot consistency.
Source
Thrown at Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiCommands.java:109
throw new RuntimeException("Trace already started");
}
}
public void resetTrace() {
trace = null;
resetTx();
}
public RmiTransaction requireTx() {
if (tx == null) {
throw new RuntimeException("No transaction");
}
return tx;
}
public void requireNoTx() {
if (tx != null) {
throw new RuntimeException("Transaction already started");
}
}
public void resetTx() {
tx = null;
}
}
public class JdiCommands {
private JdiConnector connector;
private JdiManagerImpl jdi;
public State state;
private String[] regNames = { "PC", "return_address" };
public long MAX_REFS = 100;
View on GitHub (pinned to d5f144c24d)
Solutions
- Call ghidraTraceTxCommit() or equivalent to close the open transaction, then retry the failing command.
- If the transaction is stale or the session is in an unknown state, call the reset/disconnect command to tear down State and start fresh.
- Audit your automation script to ensure every ghidraTraceTxStart() is paired with a commit in a try/finally block so exceptions don't leave tx dangling.
Example fix
// before
state.requireNoTx(); // throws if prior tx leaked
// after — guard the transaction lifecycle
try {
ghidraTraceTxStart("op");
// ... work ...
} finally {
ghidraTraceTxCommit(); // or ghidraTraceTxEnd()
} Defensive patterns
Strategy: validation
Validate before calling
// Before invoking a command that calls requireNoTx(), check State
if (state.tx != null) {
// commit or reset the dangling transaction first
ghidraTraceTxCommit(); // or state.resetTx(); if known-stale
} Prevention
- Always pair ghidraTraceTxStart() with a commit/end in a try/finally so exceptions cannot leave a transaction open.
- After any error in a trace session, explicitly reset State before issuing new commands.
- Treat a non-null tx field as an invalid precondition and resolve it before proceeding.
When it happens
Trigger: Calling any JdiCommands method that internally invokes state.requireNoTx() — such as starting a new transaction, connecting, or resetting — after ghidraTraceTxStart() (or equivalent) was called without a matching commit/rollback. Also occurs when a prior command threw an exception mid-transaction and resetTx() was never reached, leaving tx non-null for the next command.
Common situations: An earlier transaction was abandoned due to an uncaught exception in the JDI agent; the trace session was interrupted and not cleanly torn down; a script opened a transaction and forgot to call ghidraTraceTxCommit/ghidraTraceTxEnd.
Related errors
- No transaction
- Address must be in the form 'host:port'
- Port must be numeric
- Error connecting to ${address}: ${e}
- Attempt to create existing memory
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/2c4ddb993370af70.
Report an issue: GitHub.