{"record":{"id":"3d0fadf6403cd405","repo":"NationalSecurityAgency/ghidra","slug":"no-transaction-3d0fad","errorCode":null,"errorMessage":"No transaction","messagePattern":"No transaction","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-agent-x64dbg/src/main/py/src/ghidraxdbg/commands.py","lineNumber":146,"sourceCode":"\n    def require_trace(self) -> Trace[Extra]:\n        if self.trace is None:\n            raise RuntimeError(\"No trace active\")\n        return self.trace\n\n    def require_no_trace(self) -> None:\n        if self.trace != None:\n            raise RuntimeError(\"Trace already started\")\n\n    def reset_trace(self) -> None:\n        self.trace: Optional[Trace[Extra]] = None\n        util.set_convenience_variable('_ghidra_tracing', \"false\")\n        self.reset_tx()\n\n    def require_tx(self) -> Tuple[Trace, Transaction]:\n        trace = self.require_trace()\n        if self.tx is None:\n            raise RuntimeError(\"No transaction\")\n        return trace, self.tx\n\n    def require_no_tx(self) -> None:\n        if self.tx != None:\n            raise RuntimeError(\"Transaction already started\")\n\n    def reset_tx(self) -> None:\n        self.tx: Optional[Transaction] = None\n\n\nSTATE = State()\n\n\ndef ghidra_trace_connect(address: Optional[str] = None) -> None:\n    \"\"\"Connect Python to Ghidra for tracing.\n\n    Address must be of the form 'host:port'\n    \"\"\"","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-agent-x64dbg/src/main/py/src/ghidraxdbg/commands.py#L128-L164","documentation":"Raised by State.require_tx when STATE.tx is None. Transactions wrap trace mutations; they are opened via trace.open_tx (used in 'ghidra trace tx-start' / open_tracked_tx). Any method that modifies the trace calls require_tx to ensure a transaction is active before writing.","triggerScenarios":"A trace-mutation command calls STATE.require_tx() before 'ghidra trace tx-start' (or trace.open_tx) has opened a transaction. This also fires after tx-stop/reset_tx clears the transaction.","commonSituations":"User issued 'ghidra trace put-*' or other mutation commands without first opening a transaction. The transaction was committed/stopped and not reopened before the next mutation. reset_tx was called (e.g. by reset_trace) and mutations were attempted.","solutions":["Open a transaction with 'ghidra trace tx-start <description>' before issuing mutation commands.","Use the open_tracked_tx context manager to ensure the transaction lifecycle is correct.","Check STATE.tx is not None before calling require_tx-dependent commands."],"exampleFix":"# before: mutation without transaction\ntrace, tx = STATE.require_tx()  # tx is None\n\n# after: open transaction first\nwith commands.open_tracked_tx('My Operation'):\n    trace, tx = STATE.require_tx()\n    # ... perform trace mutations ...","handlingStrategy":"validation","validationCode":"if STATE.tx is None:\n    raise RuntimeError(\"No transaction; run 'ghidra trace tx-start' or use open_tracked_tx first\")","typeGuard":"def has_tx() -> bool:\n    return getattr(STATE, 'tx', None) is not None","tryCatchPattern":"try:\n    trace, tx = STATE.require_tx()\nexcept RuntimeError:\n    with commands.open_tracked_tx('Auto Transaction'):\n        trace, tx = STATE.require_tx()\n        # ... perform mutations ...","preventionTips":["Open a transaction with 'ghidra trace tx-start' or open_tracked_tx before mutation commands.","Use the open_tracked_tx context manager to manage transaction lifecycle automatically.","Check STATE.tx is not None before calling require_tx-dependent operations."],"tags":["x64dbg","debugger-agent","state-machine","runtimeerror","transaction","trace-lifecycle"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}