{"record":{"id":"0c1058d98f6d3430","repo":"YunaiV/ruoyi-vue-pro","slug":"modbus-slaveid-d-identifier-s-address-d","errorCode":null,"errorMessage":"Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]","messagePattern":"Modbus 写入失败 \\[slaveId=(.+?), identifier=(.+?), address=(.+?)\\]","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java","lineNumber":120,"sourceCode":"                                        IotModbusPointRespDTO point,\n                                        int[] values) {\n        return connection.executeBlocking(tcpConnection -> {\n            try {\n                // 1. 创建请求\n                ModbusRequest request = createWriteRequest(point.getFunctionCode(),\n                        point.getRegisterAddress(), point.getRegisterCount(), values);\n                if (request == null) {\n                    throw new RuntimeException(\"功能码 \" + point.getFunctionCode() + \" 不支持写操作\");\n                }\n                request.setUnitID(slaveId);\n\n                // 2. 执行事务（请求）\n                ModbusTCPTransaction transaction = new ModbusTCPTransaction(tcpConnection);\n                transaction.setRequest(request);\n                transaction.execute();\n                return true;\n            } catch (Exception e) {\n                throw new RuntimeException(String.format(\"Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]\",\n                        slaveId, point.getIdentifier(), point.getRegisterAddress()), e);\n            }\n        });\n    }\n\n    /**\n     * 创建读取请求\n     */\n    @SuppressWarnings(\"EnhancedSwitchMigration\")\n    private static ModbusRequest createReadRequest(Integer functionCode, Integer address, Integer count) {\n        switch (functionCode) {\n            case FC_READ_COILS:\n                return new ReadCoilsRequest(address, count);\n            case FC_READ_DISCRETE_INPUTS:\n                return new ReadInputDiscretesRequest(address, count);\n            case FC_READ_HOLDING_REGISTERS:\n                return new ReadMultipleRegistersRequest(address, count);\n            case FC_READ_INPUT_REGISTERS:","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/YunaiV/ruoyi-vue-pro/blob/0418084e222612af2fc1141f566af454f9236ab1/yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbus/common/utils/IotModbusTcpClientUtils.java#L102-L138","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before writing, validate connection + address range + value bounds\nif (!connection.isOpen()) {\n    return Future.failedFuture(new IllegalStateException(\"Modbus 连接未打开\"));\n}\nif (point.getRegisterAddress() == null || point.getRegisterAddress() < 0) {\n    return Future.failedFuture(new IllegalArgumentException(\"寄存器地址非法\"));\n}\nfor (int v : values) {\n    if (point.getFunctionCode() == 1) { if (v != 0 && v != 1) return Future.failedFuture(...); }\n    else if (v < 0 || v > 0xFFFF) { return Future.failedFuture(new IllegalArgumentException(\"寄存器值越界\")); }\n}","typeGuard":null,"tryCatchPattern":"// handle write failure; classify and retry only transient errors\nIotModbusTcpClientUtils.write(connection, slaveId, point, values)\n    .onFailure(e -> {\n        Throwable root = e.getCause() != null ? e.getCause() : e;\n        if (root instanceof java.net.SocketException) {\n            // transient — retry once after reconnect\n        } else {\n            // slave exception (illegal address/value) — do not retry; surface to user\n        }\n    });","preventionTips":["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."],"tags":["modbus","iot","network"],"backgroundTag":null,"analyzedSha":"0418084e222612af2fc1141f566af454f9236ab1","analyzedAt":"2026-08-14T00:56:18.412Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}