Skip to content

Exceptions

Both backends map their errors onto the same neutral hierarchy, so except ModbusError catches everything regardless of which backend produced it. Every ModbusUnit method raises on failure — it never returns None.

ModbusError
├── ModbusConnectionError
├── ModbusTimeoutError (also a builtin TimeoutError)
├── ModbusExceptionError (.exception_code)
└── ModbusProtocolError

Import them from the top-level package:

from modbus_connection import (
ModbusError,
ModbusConnectionError,
ModbusTimeoutError,
ModbusExceptionError,
ModbusProtocolError,
)

The base class. Catch it to handle any Modbus failure uniformly:

try:
values = await unit.read_holding_registers(0, 10)
except ModbusError as err:
log.warning("read failed: %s", err)

The link is down, not connected, or the transport failed. Recreating the connection is the owner’s job — the abstraction never self-reconnects.

An operation timed out: a request got no valid response in time, or a connect attempt did not complete in time. It also subclasses the builtin TimeoutError, so except TimeoutError catches it too:

try:
await unit.read_holding_registers(0, 1)
except TimeoutError: # catches ModbusTimeoutError
...

The device returned a Modbus exception response — it understood the request but refused it (illegal address, illegal value, and so on). The raw code is on .exception_code:

try:
await unit.write_register(40, 99)
except ModbusExceptionError as err:
if err.exception_code == 3: # illegal data value
...

A reply arrived but was not a valid frame — bad CRC/LRC, framing, or a mismatched header. Only backends that can tell a garbled reply from a missing one raise it: tmodbus does; pymodbus cannot, and surfaces both a garbled and a missing reply as ModbusTimeoutError.

Situation pymodbus tmodbus
No response in time ModbusTimeoutError ModbusTimeoutError
Garbled / corrupt reply ModbusTimeoutError ModbusProtocolError
Device exception response ModbusExceptionError ModbusExceptionError
Link down ModbusConnectionError ModbusConnectionError

If you need to distinguish a corrupt reply from a silent timeout, use tmodbus. If you catch ModbusError (or ModbusTimeoutError plus ModbusExceptionError) your code is correct on both.

A backend that can’t implement a given Modbus function code raises the builtin NotImplementedError (not part of the ModbusError tree). tmodbus does this for diagnostics and the comm-event codes, and for the UDP / ASCII-over-TCP transports.