YunaiV/ruoyi-vue-pro · error · RuntimeException
Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]
Error message
Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]
What it means
Wraps ANY exception during a Modbus TCP write transaction inside executeBlocking: createWriteRequest, transaction.execute(), or setUnitID. Like the read sibling (error 44), j2mod throws on connection loss, slave timeout, illegal data address/value exception responses, etc. The message includes slaveId/identifier/registerAddress.
Source
Thrown at yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java:120
IotModbusPointRespDTO point,
int[] values) {
return connection.executeBlocking(tcpConnection -> {
try {
// 1. 创建请求
ModbusRequest request = createWriteRequest(point.getFunctionCode(),
point.getRegisterAddress(), point.getRegisterCount(), values);
if (request == null) {
throw new RuntimeException("功能码 " + point.getFunctionCode() + " 不支持写操作");
}
request.setUnitID(slaveId);
// 2. 执行事务(请求)
ModbusTCPTransaction transaction = new ModbusTCPTransaction(tcpConnection);
transaction.setRequest(request);
transaction.execute();
return true;
} catch (Exception e) {
throw new RuntimeException(String.format("Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]",
slaveId, point.getIdentifier(), point.getRegisterAddress()), e);
}
});
}
/**
* 创建读取请求
*/
@SuppressWarnings("EnhancedSwitchMigration")
private static ModbusRequest createReadRequest(Integer functionCode, Integer address, Integer count) {
switch (functionCode) {
case FC_READ_COILS:
return new ReadCoilsRequest(address, count);
case FC_READ_DISCRETE_INPUTS:
return new ReadInputDiscretesRequest(address, count);
case FC_READ_HOLDING_REGISTERS:
return new ReadMultipleRegistersRequest(address, count);
case FC_READ_INPUT_REGISTERS:View on GitHub (pinned to 0418084e22)
Solutions
- Inspect the wrapped cause (getCause()) to distinguish a Modbus exception response (illegal address/value) from a network failure (connection reset/timeout).
- Verify the device is online and slaveId/registerAddress match the writable register map.
- Confirm values[] length matches point.registerCount and each value fits the register (0-65535 for holding registers, 0/1 for coils).
- Reproduce with an independent Modbus write tool to isolate gateway vs device.
- Add retry-with-backoff for transient connection drops.
Defensive patterns
Strategy: try-catch
Validate before calling
// before writing, validate connection + address range + value bounds
if (!connection.isOpen()) {
return Future.failedFuture(new IllegalStateException("Modbus 连接未打开"));
}
if (point.getRegisterAddress() == null || point.getRegisterAddress() < 0) {
return Future.failedFuture(new IllegalArgumentException("寄存器地址非法"));
}
for (int v : values) {
if (point.getFunctionCode() == 1) { if (v != 0 && v != 1) return Future.failedFuture(...); }
else if (v < 0 || v > 0xFFFF) { return Future.failedFuture(new IllegalArgumentException("寄存器值越界")); }
} Try / catch
// handle write failure; classify and retry only transient errors
IotModbusTcpClientUtils.write(connection, slaveId, point, values)
.onFailure(e -> {
Throwable root = e.getCause() != null ? e.getCause() : e;
if (root instanceof java.net.SocketException) {
// transient — retry once after reconnect
} else {
// slave exception (illegal address/value) — do not retry; surface to user
}
}); Prevention
- Confirm registerAddress/count are within the device's writable range.
- Validate each value fits its target (0/1 for coils, 0-65535 for registers).
- Retry writes only on transient connection errors, not on Modbus exception responses.
- Log the slaveId/identifier/address from the message for fast triage.
When it happens
Trigger: Slave offline or connection dropped mid-write; registerAddress out of range; the slave rejects the value (illegal data value exception); network interruption; writing to a read-only address on the device; count/values mismatch causing a malformed request.
Common situations: Device offline when a command is issued; writing an out-of-range value; device reboot during write; actuator address misconfigured; device rejects value beyond its accepted range.
Related errors
- Modbus 读取失败 [slaveId=%d, identifier=%s, functionCode=%d, add
- MQTT Client 启动失败: 连接 Broker 失败
- 功能码 {} 不支持写操作
- [startTcpServer][TCP Server 启动失败]
- [createProtocol][协议实例 %s 的协议类型 %s 暂不支持]
AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14).
Data as JSON: /api/errors/0c1058d98f6d3430.
Report an issue: GitHub.