NationalSecurityAgency/ghidra · error · RuntimeError
Transaction already started
Error message
Transaction already started
What it means
Raised by State.require_no_tx in the Ghidra LLDB agent when STATE.tx is already set — i.e. a transaction is already open. The start-tx command (commands.py:525 calls require_no_tx) calls this to prevent nesting two transactions; an existing open transaction is rejected with RuntimeError.
Source
Thrown at Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py:131
def require_no_trace(self) -> None:
if self.trace is not None:
raise RuntimeError("Trace already started")
def reset_trace(self) -> None:
self.trace: Optional[Trace[Extra]] = None
util.set_convenience_variable('_ghidra_tracing', "false")
self.reset_tx()
def require_tx(self) -> Tuple[Trace[Extra], Transaction]:
trace = self.require_trace()
if self.tx is None:
raise RuntimeError("No transaction")
return trace, self.tx
def require_no_tx(self) -> None:
if self.tx is not None:
raise RuntimeError("Transaction already started")
def reset_tx(self) -> None:
self.tx: Optional[Transaction] = None
STATE = State()
if __name__ == '__main__':
lldb.SBDebugger.InitializeWithErrorHandling()
lldb.debugger = lldb.SBDebugger.Create()
elif lldb.debugger:
lldb.debugger.HandleCommand(
'command container add -h "Commands for connecting to Ghidra" ghidra')
lldb.debugger.HandleCommand(
'command container add -h "Commands for exporting data to a Ghidra trace" ghidra trace')
lldb.debugger.HandleCommand(
'command container add -h "Utility commands for testing with Ghidra" ghidra util')
View on GitHub (pinned to d5f144c24d)
Solutions
- Commit/close the current transaction (ghidra_trace_tx_commit, commands.py:542) before starting a new one.
- Use STATE.require_trace().open_tx(description) as a context manager so the tx always closes on block exit.
- Catch RuntimeError and hint 'transaction already started; run ghidra_trace_tx_commit first'.
- Ensure reset_tx is invoked after commit so STATE.tx returns to None.
Example fix
// before
STATE.require_no_tx()
STATE.tx = STATE.require_trace().start_tx(description, undoable=False)
// after
if STATE.tx is not None:
STATE.require_tx()[1].commit()
STATE.reset_tx()
STATE.require_no_tx()
STATE.tx = STATE.require_trace().start_tx(description, undoable=False) Defensive patterns
Strategy: validation
Validate before calling
if STATE.tx is not None:
STATE.require_tx()[1].commit()
STATE.reset_tx()
STATE.require_no_tx()
STATE.tx = STATE.require_trace().start_tx(description, undoable=False) Type guard
def no_tx_open() -> bool:
return STATE.tx is None Try / catch
try:
STATE.require_no_tx()
except RuntimeError:
print("Transaction already started; run ghidra_trace_tx_commit first")
return Prevention
- commit/close the current tx before starting a new one
- use open_tx context managers
- call reset_tx after commit
When it happens
Trigger: Running the start-tx command a second time without first committing/closing the existing transaction. The start-tx command asserts require_no_tx before opening a new Transaction.
Common situations: User runs 'ghidra_trace_tx_start' twice; previous tx was not committed (ghidra_trace_tx_commit); script opens a second tx without closing the first.
Related errors
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/1fad6e21a012c9d9.
Report an issue: GitHub.