--- title: Error Handling description: Exception hierarchy and error recovery patterns --- import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; openocd-python uses a structured exception hierarchy rooted at `OpenOCDError`. Every exception the library raises is a subclass of this base, so you can catch broadly or narrowly depending on your needs. ## Exception hierarchy ``` OpenOCDError ├── ConnectionError # TCP connection failures ├── TimeoutError # Deadline exceeded ├── TargetError # Target not responding or returned an error │ └── TargetNotHaltedError # Operation requires halted target ├── FlashError # Flash operation failed ├── JTAGError # JTAG communication error ├── SVDError # SVD file or parsing error ├── ProcessError # OpenOCD subprocess failed └── BreakpointError # Breakpoint/watchpoint operation failed ``` All exceptions are importable from the top-level `openocd` package: ```python from openocd import ( OpenOCDError, ConnectionError, TimeoutError, TargetError, TargetNotHaltedError, FlashError, JTAGError, SVDError, ProcessError, ) ``` ## Exception details ### OpenOCDError The base class for all library exceptions. Catching this handles any error that openocd-python can raise: ```python from openocd import OpenOCDError, Session with Session.connect_sync() as ocd: try: state = ocd.target.state() except OpenOCDError as e: print(f"Something went wrong: {e}") ``` ### ConnectionError Raised when a TCP connection to OpenOCD cannot be established. Common causes: - OpenOCD is not running - Wrong host or port - Firewall blocking the connection - Network unreachable ```python from openocd import ConnectionError, Session try: with Session.connect_sync(host="192.168.1.99", port=6666) as ocd: ocd.target.state() except ConnectionError as e: print(f"Cannot reach OpenOCD: {e}") ``` Also raised if a command is sent after the connection has been closed, or if OpenOCD closes the connection unexpectedly during a read. ### TimeoutError Raised when an operation exceeds its deadline. This can happen during: - Initial connection (`Session.connect()` with `timeout` parameter) - Waiting for OpenOCD to start (`Session.start()` with `timeout` parameter) - Individual command responses (the `TclRpcConnection` timeout) - `target.wait_halt()` when the target does not halt in time ```python from openocd import TimeoutError, Session with Session.connect_sync() as ocd: try: # Wait up to 2 seconds for the target to halt ocd.target.wait_halt(timeout_ms=2000) except TimeoutError: print("Target did not halt within 2 seconds") ``` ### TargetError Raised when a target command fails. The error message contains the raw OpenOCD response for diagnosis. This covers halt, resume, step, reset, memory read/write, and register access failures. ```python from openocd import TargetError, Session with Session.connect_sync() as ocd: try: ocd.target.halt() except TargetError as e: print(f"Target command failed: {e}") ``` ### TargetNotHaltedError A subclass of `TargetError`, raised specifically when an operation requires a halted target but the target is running. This is most commonly encountered when reading or writing registers. ```python from openocd import TargetNotHaltedError, Session with Session.connect_sync() as ocd: try: pc = ocd.registers.pc() except TargetNotHaltedError: print("Halt the target first before reading registers") ocd.target.halt() pc = ocd.registers.pc() ``` Because `TargetNotHaltedError` is a subclass of `TargetError`, catching `TargetError` will also catch it: ```python try: pc = ocd.registers.pc() except TargetNotHaltedError: # Handle the specific case ocd.target.halt() pc = ocd.registers.pc() except TargetError: # Handle other target errors print("Unexpected target error") ``` ### FlashError Raised when a flash operation fails -- programming, erasing, verifying, or reading flash memory. The error message includes the raw OpenOCD response. ```python from openocd import FlashError, Session from pathlib import Path with Session.connect_sync() as ocd: try: ocd.flash.write_image(Path("firmware.bin")) except FlashError as e: print(f"Flash programming failed: {e}") ``` Also raised for: - Invalid sector ranges (e.g., `first > last` in `erase_sector`) - Verification mismatches after `write_image` with `verify=True` - Unparseable flash info output ### JTAGError Raised when JTAG communication fails. This covers chain scan errors, TAP state transitions, and raw scan operations. ```python from openocd import JTAGError, Session with Session.connect_sync() as ocd: try: taps = ocd.jtag.scan_chain() except JTAGError as e: print(f"JTAG error: {e}") ``` ### SVDError Raised when SVD-related operations fail: - SVD file not found or cannot be parsed - Peripheral name not found in the loaded SVD - Register name not found within a peripheral - No SVD file loaded when trying to list or decode ```python from openocd import SVDError, Session from pathlib import Path with Session.connect_sync() as ocd: try: ocd.svd.load(Path("nonexistent.svd")) except SVDError as e: print(f"SVD error: {e}") ``` ### ProcessError Raised when the OpenOCD subprocess fails to start or exits unexpectedly. This only applies when using `Session.start()`. ```python from openocd import ProcessError, Session try: with Session.start_sync("nonexistent_config.cfg") as ocd: pass except ProcessError as e: print(f"OpenOCD failed to start: {e}") ``` Common causes: - OpenOCD binary not found on `PATH` - Invalid configuration file - OpenOCD exits before the TCL RPC port is ready - Permission errors ### BreakpointError Raised when a breakpoint or watchpoint operation fails. Defined in `openocd.breakpoints` but inherits from `OpenOCDError`. ```python from openocd.breakpoints import BreakpointError from openocd import Session with Session.connect_sync() as ocd: try: ocd.breakpoints.add(0x08001234, length=2, hw=True) except BreakpointError as e: print(f"Breakpoint error: {e}") ``` ## Catching patterns ### Broad catch -- handle any library error ```python from openocd import OpenOCDError, Session with Session.connect_sync() as ocd: try: ocd.target.halt() pc = ocd.registers.pc() data = ocd.memory.read_u32(pc, count=4) except OpenOCDError as e: print(f"Operation failed: {e}") ``` ### Narrow catch -- handle specific failure modes ```python from openocd import ( Session, ConnectionError, TargetError, TargetNotHaltedError, TimeoutError, ) try: with Session.connect_sync() as ocd: ocd.target.halt() pc = ocd.registers.pc() ocd.target.resume() except ConnectionError: print("Could not connect to OpenOCD") except TargetNotHaltedError: print("Target is not halted") except TimeoutError: print("Operation timed out") except TargetError as e: print(f"Target error: {e}") ``` ### Retry pattern ```python from openocd import Session, TimeoutError with Session.connect_sync() as ocd: for attempt in range(3): try: ocd.target.halt() ocd.target.wait_halt(timeout_ms=1000) break except TimeoutError: if attempt == 2: raise print(f"Attempt {attempt + 1} timed out, retrying...") ocd.target.reset(mode="halt") ``` ### Recovery from TargetNotHaltedError A common pattern is to attempt a register read and automatically halt if needed: ```python from openocd import Session, TargetNotHaltedError def safe_read_pc(ocd) -> int: try: return ocd.registers.pc() except TargetNotHaltedError: ocd.target.halt() return ocd.registers.pc() with Session.connect_sync() as ocd: pc = safe_read_pc(ocd) print(f"PC = 0x{pc:08X}") ``` ## Error responses from OpenOCD Internally, most subsystems detect errors by checking for the word "error" in the OpenOCD response string. This is because OpenOCD's TCL RPC protocol does not use structured error codes -- all errors are communicated as plain text in the response body. The library wraps these text responses in the appropriate exception type so you do not need to parse them yourself. The original OpenOCD message is preserved in the exception's string representation. ## Next steps - [Target Control](/guides/target-control/) -- which methods raise which exceptions - [Memory Operations](/guides/memory-operations/) -- error handling for memory reads and writes - [Session Lifecycle](/guides/session-lifecycle/) -- connection and process errors