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

  1. Call ghidraTraceTxCommit() or equivalent to close the open transaction, then retry the failing command.
  2. 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.
  3. 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

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


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/2c4ddb993370af70. Report an issue: GitHub.