YunaiV/yudao-cloud · error · IllegalArgumentException

不支持的功能码: {}

Error message

不支持的功能码: {}

What it means

IotModbusTcpClientUtils.createReadRequest switches on the function code and only maps the four Modbus read codes — FC_READ_COILS (01), FC_READ_DISCRETE_INPUTS (02), FC_READ_HOLDING_REGISTERS (03), FC_READ_INPUT_REGISTERS (04). Any other value (write codes 05/06/0F/10, 0, null, or exotic codes) hits the default branch and throws IllegalArgumentException '不支持的功能码'. The code comes from the IoT thing-model point configuration.

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:141

        });
    }

    /**
     * 创建读取请求
     */
    @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:
                return new ReadInputRegistersRequest(address, count);
            default:
                throw new IllegalArgumentException("不支持的功能码: " + functionCode);
        }
    }

    /**
     * 创建写入请求
     */
    @SuppressWarnings("EnhancedSwitchMigration")
    private static ModbusRequest createWriteRequest(Integer functionCode, Integer address, Integer count, int[] values) {
        switch (functionCode) {
            case FC_READ_COILS: // 写线圈(使用功能码 5 或 15)
                if (count == 1) {
                    return new WriteCoilRequest(address, values[0] != 0);
                } else {
                    BitVector bv = new BitVector(count);
                    for (int i = 0; i < Math.min(values.length, count); i++) {
                        bv.setBit(i, values[i] != 0);
                    }
                    return new WriteMultipleCoilsRequest(address, bv);

View on GitHub (pinned to 477be9dd49)

Solutions

  1. Set the point's function code to one of 1, 2, 3, 4 for readable points
  2. Use write codes (5, 6, 15, 16) only for points that are written, and never route reads to them
  3. Validate the FC column when importing points in bulk (1-4 for read, 5/6/15/16 for write)

Example fix

// before: holding-register point given a write FC
{"identifier":"temp","functionCode":6}

// after
{"identifier":"temp","functionCode":3} // FC3 = read holding registers
Defensive patterns

Strategy: type-guard

Validate before calling

Set<Integer> READABLE_FC = Set.of(1, 2, 3, 4);
if (!READABLE_FC.contains(point.getFunctionCode())) {
    throw new IllegalArgumentException("点位 functionCode=" + point.getFunctionCode()
        + " 不支持读取 (需 01/02/03/04)");
}

Type guard

boolean isReadableFunctionCode(Integer fc) {
    return fc != null && Set.of(1, 2, 3, 4).contains(fc);
}

Prevention

When it happens

Trigger: A read/poll issued against a point whose functionCode is a write code (05, 06, 15, 16); point created with functionCode 0/null; typo in the FC field during bulk point import; using a nonstandard vendor FC.

Common situations: Bulk-importing thing model points with wrong FC column; copy-pasting a register point and forgetting to change its FC; device doc listing decimal vs hex FCs (16 entered where 0x10=16 is meant inconsistently).

Related errors


AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14). Data as JSON: /api/errors/64d8749049be0da0. Report an issue: GitHub.