NationalSecurityAgency/ghidra · error · RuntimeError

No transaction

Error message

No transaction

What it means

Raised by State.require_tx in the Ghidra LLDB agent when STATE.tx is None — i.e. no transaction is currently open on the trace. Commands that mutate the trace (putmem, regs, objects, snapshots written under tx) call require_tx to obtain a (trace, tx) pair; without an open transaction, writes are disallowed. RuntimeError signals a lifecycle precondition: a transaction must be started (commands.py:525-526, start_tx) before mutating commands.

Source

Thrown at Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py:126

    def require_trace(self) -> Trace[Extra]:
        if self.trace is None:
            raise RuntimeError("No trace active")
        return self.trace

    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')

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Open a transaction (ghidra_trace_tx_start) before any mutating command, and commit/close it (ghidra_trace_tx_commit) when done.
  2. Prefer STATE.require_trace().open_tx(description) as a context manager so the tx always closes.
  3. Catch RuntimeError and hint 'no transaction; run ghidra_trace_tx_start'.
  4. Ensure tx is reset (reset_tx) after commit so stale state does not confuse subsequent checks.

Example fix

// before
trace, tx = STATE.require_tx()
// after
if STATE.tx is None:
    print("No transaction. Run: ghidra_trace_tx_start <description>")
    return
trace, tx = STATE.require_tx()
Defensive patterns

Strategy: validation

Validate before calling

if STATE.tx is None:
    print("No transaction. Run: ghidra_trace_tx_start <description>")
    return
trace, tx = STATE.require_tx()

Type guard

def tx_open() -> bool:
    return STATE.tx is not None

Try / catch

try:
    trace, tx = STATE.require_tx()
except RuntimeError:
    print("No transaction; run ghidra_trace_tx_start first")
    return

Prevention

When it happens

Trigger: Running a mutating trace command (e.g. putmem, putregs, object creation) outside of a started transaction — before 'ghidra_trace_tx_start' opened one. require_tx also internally calls require_trace, so a missing trace surfaces as 196 first. Reached by the many commands calling STATE.require_tx().

Common situations: User issued put/record commands before opening a transaction; transaction was committed/closed and user continued mutating; script that writes without tx.

Related errors


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