Skip to content

Exceptions

Structured exception hierarchy for distinguishing error categories.


Design Intent

All kazunoko exceptions inherit from KazunokoError, so callers can catch everything with one clause or handle specific categories selectively. Timeout errors are subclasses of their parent error type (not a separate branch) so a catch on ResponseError also catches ResponseTimeout.


Hierarchy

KazunokoError
├── DeviceError          — connection and port initialization failures
├── CommandError         — failures sending a command to the device
│   └── CommandTimeout   — command send timed out
├── ResponseError        — invalid or missing response from device
│   └── ResponseTimeout  — no response received within timeout
└── ProtocolError        — JSON parse failure or unexpected protocol data

Exception reference

Exception When raised Typical cause
DeviceError connect(), PortDevice.__init__ Port not found, port in use, driver missing
CommandError send_command() Device disconnected mid-session
CommandTimeout send_command() Device unresponsive
ResponseError receive_response() Malformed JSON, missing type field
ResponseTimeout receive_response() No data within timeout seconds
ProtocolError parse_jsonl() JSON parse failure, type mismatch

Usage patterns

Catch all kazunoko errors:

from kazunoko.exceptions import KazunokoError

try:
    with connect() as device:
        response = device.query("GET_STATUS")
except KazunokoError as e:
    print(f"Error: {e}")

Handle specific categories:

from kazunoko.exceptions import DeviceError, ResponseTimeout, ResponseError

try:
    with connect() as device:
        response = device.query("GET_STATUS")
except DeviceError as e:
    print(f"Could not connect: {e}")
except ResponseTimeout:
    print("Device did not respond — try kazunoko reset")
except ResponseError as e:
    print(f"Invalid response: {e}")

Exception chaining — kazunoko exceptions always chain the underlying cause (raise KazunokoError(...) from e), so the original serial.SerialException or json.JSONDecodeError is accessible via e.__cause__ for debugging.


Streaming and skipped events

In streaming contexts (Reader, Measure), ResponseTimeout and ProtocolError are caught internally — the event is skipped and counted in StreamingStats rather than aborting the whole collection. DeviceError and CommandError are not caught and propagate immediately, since they indicate the connection itself has failed.