{"record":{"id":"63a263d5ec8d00f9","repo":"NationalSecurityAgency/ghidra","slug":"transaction-already-started-63a263","errorCode":null,"errorMessage":"Transaction already started","messagePattern":"Transaction already started","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-agent-drgn/src/main/py/src/ghidradrgn/commands.py","lineNumber":138,"sourceCode":"\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    \"\"\"\n    Connect Python to Ghidra for tracing\n\n    Address must be of the form 'host:port'\n    \"\"\"\n\n    STATE.require_no_client()\n    if address is None:\n        raise RuntimeError(","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-agent-drgn/src/main/py/src/ghidradrgn/commands.py#L120-L156","documentation":"Raised as RuntimeError by State.require_no_tx() when STATE.tx is already set — a transaction is open and nesting is not allowed. Attempting to open a second transaction before the first closes triggers it.","triggerScenarios":"Calling open_tx() (or a helper that opens one) while already inside an open_tx block.","commonSituations":"Nested open_tx() calls; a helper that opens its own tx invoked from within another tx; a tx left open by an exception.","solutions":["Re-use the existing open transaction instead of opening a nested one.","Guard: if STATE.tx is not None: perform the work in the current tx rather than opening another.","Ensure earlier open_tx blocks are exited (context manager) before starting a new one."],"exampleFix":"// before\nwith trace.open_tx('outer'):\n    with trace.open_tx('inner'):  # RuntimeError: Transaction already started\n        ...\n// after\nwith trace.open_tx('outer'):\n    ...  # do inner work in the same transaction","handlingStrategy":"validation","validationCode":"if STATE.tx is not None:\n    raise RuntimeError('a transaction is already open; reuse it instead of nesting')","typeGuard":"def no_open_transaction() -> bool:\n    return getattr(STATE, 'tx', None) is None","tryCatchPattern":"try:\n    with trace.open_tx('op'):\n        do_work(trace)\nexcept RuntimeError as e:\n    if 'Transaction already started' in str(e):\n        do_work(trace)  # reuse the ambient transaction\n    else:\n        raise","preventionTips":["Never nest open_tx() blocks; reuse the ambient transaction.","Ensure helpers that open their own tx are not called from within an open tx.","Make sure earlier open_tx blocks exit (context manager) before starting new ones."],"tags":["drgn","transaction","state-machine","precondition"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}