Modbus Exception Codes Explained — What They Mean & How to Fix

Every Modbus exception response boils down to one byte after the function code. This reference explains what each exception code actually means, why it happens in real integrations, and exactly how to fix it — with byte-level request/response examples for every code you'll realistically encounter.

How Exception Responses Work

When a Modbus slave can't process a request, it doesn't just stay silent — it sends back a specific exception response so the master knows exactly what went wrong. The structure is always the same: the function code byte with its high bit set (function code OR 0x80), followed by a single exception code byte.

Exception response structure:
Byte 0: Function Code | 0x80
Byte 1: Exception Code

Example — a FC03 (0x03) request that fails:
83 02   → FC03 exception, code 0x02 (Illegal Data Address)

This matters because 0x83 is easy to misread as garbage data if you're not expecting it. If the first byte of a response has its top bit set, you're looking at an exception, not a normal read/write result — check the second byte before doing anything else.

0x01 — Illegal Function

The slave doesn't implement the function code you sent at all. This is a capability mismatch, not a data problem.

Request — FC04 (Read Input Registers) to a device that only supports FC03:
04 00 00 00 02

Response:
84 01   → FC04 exception, code 0x01 (Illegal Function)

Fix: Check the device's Modbus register map documentation for which function codes it actually supports. Many low-cost sensors and energy meters only implement FC03 (Read Holding Registers) and FC06/FC16 (write), and map every value — including analog inputs — as holding registers rather than using FC04.

0x02 — Illegal Data Address

This is the exception you'll see most often. The starting address plus the quantity requested falls outside the range of registers, coils, or inputs the device actually has.

Request — read 10 holding registers starting at address 200 on a device
that only has 100 registers defined:
03 00 C8 00 0A

Response:
83 02   → FC03 exception, code 0x02 (Illegal Data Address)

Fix: This is almost always one of two things. First, an off-by-one error — Modbus documentation numbers registers starting at 1 (e.g. 40001), but the address on the wire is 0-based (PDU address 0). Second, requesting more registers than the device implements in one call — always cross-check against the device's published register map before assuming your master code is broken.

0x03 — Illegal Data Value

The address is valid, but the value in the request's data field isn't something the device will accept.

Request — FC05 (Write Single Coil) with an invalid value (only 0xFF00
and 0x0000 are legal):
05 00 10 12 34

Response:
85 03   → FC05 exception, code 0x03 (Illegal Data Value)

Fix: For FC05, only send exactly 0xFF00 (ON) or 0x0000 (OFF) — anything else triggers 0x03. For FC03/FC16, requesting a quantity above the protocol limit (125 registers for reads, 123 for writes) also returns this code, even if the starting address is valid.

0x04 — Slave Device Failure

The request was well-formed and the address was valid, but the slave hit an internal error trying to actually execute it — a hardware fault, a sensor out of its calibrated range, or a firmware bug.

Fix: This isn't something your master application can fix by retrying the same request. Check the physical device — power cycle it, check sensor wiring, or check the manufacturer's error log if the device exposes one. Persistent 0x04 responses on the same register usually point to a hardware issue, not a protocol issue.

0x05 & 0x06 — Acknowledge / Slave Busy

These two are related: the slave accepted the request but can't complete it immediately.

  • 0x05 (Acknowledge) — the slave has accepted a long-duration command and is processing it in the background. It's telling the master "I got it, give me time."
  • 0x06 (Slave Device Busy) — the slave is currently executing a long-duration program (firmware update, calibration, file transfer) and cannot accept the new request at all right now.

Fix: Both codes mean "retry later," not "this request is wrong." Implement a retry with a short backoff (typically 1-5 seconds) rather than treating either as a hard error or logging it as a fault.

0x0A & 0x0B — Gateway Exceptions

These only appear when you're going through a Modbus gateway (e.g. a TCP-to-RTU bridge) rather than talking to a device directly.

  • 0x0A (Gateway Path Unavailable) — the gateway itself is misconfigured or overloaded and can't route the request onward.
  • 0x0B (Gateway Target Device Failed to Respond) — the gateway forwarded the request fine, but the actual end device on the serial line never responded (different from the gateway itself failing).

Fix: 0x0A means check the gateway's own configuration and network connectivity. 0x0B means the problem is downstream of the gateway — check the RTU wiring, baud rate, and unit ID of the target device on the serial segment.

Quick Reference Table

CodeNameTypical CauseFix Direction
0x01Illegal FunctionDevice doesn't support this FCUse a different function code
0x02Illegal Data AddressAddress/quantity out of rangeCheck register map, fix addressing
0x03Illegal Data ValueValue or quantity not allowedCheck value constraints for that FC
0x04Slave Device FailureInternal hardware/firmware errorCheck the physical device
0x05AcknowledgeLong operation accepted, in progressRetry after a delay
0x06Slave Device BusySlave mid-operation, can't accept nowRetry after a delay
0x08Memory Parity ErrorParity error in extended memoryCheck device diagnostics
0x0AGateway Path UnavailableGateway misconfigured/overloadedCheck gateway config
0x0BGateway Target No ResponseEnd device didn't respond via gatewayCheck serial wiring/baud/unit ID

Testing Exception Handling Without Hardware

Most integration bugs around exception handling only surface when something unexpected happens on a live system — which is exactly the wrong time to discover your master application crashes on a 0x02 response instead of logging it and retrying gracefully.

With ModbusSimulator, you can:

  • Configure exactly which registers, coils, and inputs exist, then deliberately request outside that range to trigger 0x02 on demand
  • Send values that violate FC05/FC06/FC16 constraints to trigger 0x03 and confirm your master rejects or retries correctly
  • Verify your polling logic doesn't crash, hang, or misinterpret an 0x8X byte as valid register data
  • Test both Modbus TCP and Modbus RTU exception behavior with the same simulator, without needing separate hardware for each

This matters because exception handling is exactly the kind of code path that rarely gets exercised in normal testing but shows up the moment a sensor goes offline or a register map changes in the field.

Test Every Modbus Exception Path

ModbusSimulator lets you trigger every exception code on demand — no need to wait for a real device to fail in production.

Download Free Trial

For the full function code reference these exceptions map to, see Modbus Function Codes Explained. If you're chasing a specific symptom like a device that never responds at all, see Modbus Slave Not Responding — Checklist or the broader Modbus Troubleshooting: Common Errors and Fixes guide.

Frequently Asked Questions

What does Modbus exception code 0x02 mean?

Exception code 0x02 (Illegal Data Address) means the starting address plus the requested quantity falls outside the range of registers, coils, or inputs the device actually implements. It's the most common Modbus exception — usually an off-by-one addressing error or a read past the end of the device's register map.

What does Modbus exception code 0x01 mean?

Exception code 0x01 (Illegal Function) means the slave device does not support the function code you sent. Sending FC04 to a device that only implements FC03 returns 0x01 — check the device manual for supported function codes.

How do I identify an exception response on the wire?

The function code byte has its most significant bit set — the original function code OR'd with 0x80. A FC03 request that fails returns 0x83 as the first byte, followed by a single exception code byte.

What is the difference between exception code 0x02 and 0x03?

0x02 (Illegal Data Address) means the register address is out of range. 0x03 (Illegal Data Value) means the address is valid but the value being written isn't — for example an invalid FC05 coil value or requesting more than 125 registers in one FC03 read.

Why do I get exception code 0x06 (Slave Device Busy)?

0x06 means the slave received a valid request but is mid-way through a long-running operation and cannot respond to new requests yet. The correct handling is to retry after a short delay, not treat it as a hard failure.

Can I simulate exception responses without real hardware?

Yes. A Modbus simulator like ModbusSimulator lets you configure exactly which registers exist, so requesting an out-of-range address naturally triggers exception 0x02 the same way a real device would.