Errors and exceptions
Exception hierarchy
All library exceptions below extend the checked ModbusException.
| Exception | Produced by | Information |
|---|---|---|
ModbusConnectException |
Supplied serial transports when opening the port fails | Message/cause; a failed openPort() includes the port and last error code |
ModbusCrcException |
RTU client when a received frame's CRC differs | getFrame() returns the rejected RTU frame; synchronous typed calls wrap it in ModbusExecutionException |
ModbusExecutionException |
Synchronous client wrapper for unexpected connection, transport, serialization, correlation, or interruption failures | Inspect getCause(); interruption also restores the thread interrupt flag |
ModbusResponseException |
Typed client for a Modbus exception response; server services to request a Modbus exception response | getFunctionCode() and getExceptionCode(); see the RTU exception-code limitation |
ModbusTimeoutException |
Synchronous request when the configured request deadline expires | Cause is the internal TimeoutException |
UnknownUnitIdException |
Server service cannot route the requested unit | Unit ID appears in the message; supplied transports ignore the request |
Synchronous connect() wraps a transport connection failure in ModbusExecutionException. For a
serial transport, the cause can be ModbusConnectException; Netty TCP supplies its underlying
connect or TLS-handshake cause. Code using the transport stage directly or asynchronous client
stages may observe that cause instead. Synchronous request methods specifically translate timeouts
and Modbus exception responses before applying the general execution wrapper.
RTU exception-code limitation
For typed TCP responses, ModbusResponseException.getExceptionCode() contains the byte following
the exception function code. The current RTU client decoder instead records the exception-function
byte itself as the exception code, and it records that byte sign-extended — for exception function
0x83 the returned value is -125, not 131 — so the value is typically negative in logs. RTU
applications should not branch on getExceptionCode() until that implementation limitation is
fixed; use endpoint diagnostics or a frame capture when the exact RTU exception code is required.
This section is the canonical statement of the limitation; other pages link here.
Modbus exception response codes
ExceptionCode recognizes the following on-wire codes.
| Code | Enum value | Meaning |
|---|---|---|
0x01 |
ILLEGAL_FUNCTION |
Function is not allowed/supported by the server |
0x02 |
ILLEGAL_DATA_ADDRESS |
Address plus transfer length is not allowed |
0x03 |
ILLEGAL_DATA_VALUE |
Request data structure or value is not allowed |
0x04 |
SLAVE_DEVICE_FAILURE |
Server failed while performing the action |
0x05 |
ACKNOWLEDGE |
Long-running specialized command was accepted |
0x06 |
SLAVE_DEVICE_BUSY |
Server is busy with a long-running command |
0x08 |
MEMORY_PARITY_ERROR |
Specialized file-record memory consistency failure |
0x0A |
GATEWAY_PATH_UNAVAILABLE |
Gateway could not allocate a path to the target |
0x0B |
GATEWAY_TARGET_DEVICE_FAILED_TO_RESPONSE |
Gateway received no response from its target |
ExceptionCode.from(int) returns an empty Optional for unknown codes. A
ModbusResponseException still preserves an unknown numeric code and labels it UNKNOWN in its
message.
Typed TCP response validation
| Response condition | Result |
|---|---|
| Matching function code | Decode with configured response serializer |
Request function code plus 0x80 and exception byte |
ModbusResponseException |
| Exception function code without an exception byte | ModbusException for malformed exception PDU |
| Empty typed response PDU | ModbusException for empty response PDU |
| Any other function code | ModbusException for unexpected function code |
| No response before deadline | Timeout; synchronous API exposes ModbusTimeoutException |
Raw TCP calls return the response PDU bytes without these typed checks.
Server error behavior
| Server condition | Supplied behavior |
|---|---|
Service throws ModbusResponseException |
Encode standard exception PDU and keep processing |
Service throws UnknownUnitIdException |
Transport logs at debug and sends no response |
| Unsupported typed function through default service | ILLEGAL_FUNCTION exception response, for the ten typed function codes only |
| Function code without default serializer support | Request decode fails before dispatch and enters the transport error path: the Netty TCP transport closes the client channel; serial drops the frame. No exception response is sent |
| Other handler/codec exception on Netty TCP | Log error and close the client channel |
| RTU parse error over TCP | Log, reset parser, and close the client channel |
Diagnostic handling
| Failure category | Application action |
|---|---|
| Connection/open failure | Inspect nested cause and endpoint/port/serial/TLS configuration before retrying |
| Timeout | Verify unit, framing, address, server load, and timeout budget; do not retry writes blindly |
| Modbus response exception | For typed TCP, branch on numeric exception code and function; for RTU, use endpoint/frame diagnostics — see the RTU exception-code limitation |
| CRC/synchronization failure | Stop concurrent RTU requests, inspect the link, then allow parser reset/reconnect before retrying |
| Interrupted synchronous call | Treat it as a cancellation: stop the operation and propagate the interrupt; the library restores the thread's interrupt flag |