ModPackQTModPackQT
Node-RED ExamplesResourcesSign up
HomeResourcesNode-RED ExamplesHandle Modbus Exceptions and Timeouts Cleanly
IntegrationNode-RED Modbus Example

Handle Modbus Exceptions and Timeouts Cleanly

Modbus communication fails — devices go offline, CRC errors happen, exception responses arrive. This example adds a catch node and a state machine to distinguish between a Modbus exception (device replied with an error) and a timeout (device did not reply), and handles each gracefully.

What you need

  • Node-RED v3+
  • node-red-contrib-modbus installed
  • Any Modbus device (intentionally power it off to test timeout handling)

Flow Overview


                     ┌──────────────────────────────┐
                     │ Modbus Flex Getter            │
Poll 5s ────────────▶│ port 1: data (success)       │──▶ fn Success ──▶ Debug
                     │ port 2: error (fail/timeout) │──▶ fn Classify ──▶ Debug
                     └──────────────────────────────┘

Port 2 receives:
  · Exception response → msg.error.message contains "Exception 0x02"
  · Timeout           → msg.error.message contains "Timed out"
  · Connection error  → msg.error.message contains "ECONNREFUSED"

Node-RED Flow JSON

Node-RED Flow JSON
[
  {"id":"inj15","type":"inject","name":"Poll 5s","repeat":"5","once":true,"wires":[["req15"]],"x":120,"y":1500},
  {"id":"req15","type":"modbus-flex-getter","name":"Read reg","dataType":"HoldingRegister","adr":0,"quantity":1,"server":"srv1","wires":[["fn15ok"],["fn15err"]],"x":310,"y":1500},
  {"id":"fn15ok","type":"function","name":"Success","func":"context.set('status','ok');
msg.payload = msg.payload.data[0];
return msg;","wires":[["dbg15"]],"x":510,"y":1480},
  {"id":"fn15err","type":"function","name":"Classify error","func":"const isException = msg.error && msg.error.message.includes('Exception');
context.set('status', isException ? 'exception' : 'timeout');
node.warn('Modbus ' + (isException?'exception':'timeout') + ': ' + msg.error.message);
msg.payload = { error: isException ? 'exception':'timeout', msg: msg.error.message };
return msg;","wires":[["dbg15"]],"x":510,"y":1520},
  {"id":"dbg15","type":"debug","name":"Output","active":true,"complete":"payload","wires":[],"x":720,"y":1500},
  {"id":"srv1","type":"modbus-client","name":"My Slave","clienttype":"tcp","tcpHost":"192.168.1.100","tcpPort":502,"unit_id":1,"timeout":3000}
]

To import: open Node-RED → Hamburger menu → Import → paste this JSON → Deploy.

Expected Output

// On success:   msg.payload = 1234
// On exception: msg.payload = { error:'exception', msg:'Modbus exception 0x02' }
// On timeout:   msg.payload = { error:'timeout',   msg:'Timed out after 3000ms' }

Common Gotchas

  • modbus-flex-getter has TWO output ports — wire both: port 1 for data, port 2 for errors. Wiring only port 1 means errors are silently dropped.
  • Timeouts and exceptions come through port 2; do not use a catch node as the primary error handler.
  • Increase the timeout for slow RTU-to-TCP gateways or long RS-485 cables (3000–5000 ms is typical).
  • An ECONNREFUSED error means the TCP connection was refused — check IP, port, and firewall rules.
  • If a device consistently returns exception 02 on a specific address, the datasheet address is likely 1-based — subtract 1.

Same in ModPackQT — in 30 seconds

ModPackQT shows Modbus exception codes and timeout events in the console log with timestamps and decoded meanings — no custom error wiring required. Visit the Troubleshooting guide for the full list of exception codes and fixes.

Was this example helpful?

More Integration examples

All Node-RED Modbus Examples (30)

ModPackQT · Node-RED Modbus Examples · Updated 2026