YunaiV/yudao-cloud · error · IllegalArgumentException
不支持的设备范围:
Error message
不支持的设备范围:
What it means
Thrown at the end of IotOtaTaskServiceImpl.validateOtaTaskDeviceScope when createReqVO.getDeviceScope() matches neither IotOtaTaskDeviceScopeEnum.SELECT nor IotOtaTaskDeviceScopeEnum.ALL. The method branches on those two known scope values; any other value falls through to `throw new IllegalArgumentException("不支持的设备范围:" + scope)`. Because it is an IllegalArgumentException (not a framework ErrorCodeException), it bypasses the project's GlobalExceptionHandler error-code mapping and surfaces as an unhandled 500.
Source
Thrown at yudao-module-iot/yudao-module-iot-server/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaTaskServiceImpl.java:156
return devices;
}
// 情况二:全部设备
if (Objects.equals(createReqVO.getDeviceScope(), IotOtaTaskDeviceScopeEnum.ALL.getScope())) {
List<IotDeviceDO> devices = deviceService.getDeviceListByProductId(productId);
// 2.1.1 移除已经是该固件版本的设备
devices.removeIf(device -> Objects.equals(device.getFirmwareId(), createReqVO.getFirmwareId()));
// 2.1.2 移除已经在升级中的设备
List<IotOtaTaskRecordDO> records = otaTaskRecordService.getOtaTaskRecordListByDeviceIdAndStatus(
convertSet(devices, IotDeviceDO::getId), IotOtaTaskRecordStatusEnum.IN_PROCESS_STATUSES);
devices.removeIf(device -> CollUtil.contains(records,
item -> item.getDeviceId().equals(device.getId())));
// 2.2 校验是否有可升级的设备
if (CollUtil.isEmpty(devices)) {
throw exception(OTA_TASK_CREATE_FAIL_DEVICE_EMPTY);
}
return devices;
}
throw new IllegalArgumentException("不支持的设备范围:" + createReqVO.getDeviceScope());
}
private IotOtaTaskDO validateUpgradeTaskExists(Long id) {
IotOtaTaskDO upgradeTask = otaTaskMapper.selectById(id);
if (Objects.isNull(upgradeTask)) {
throw exception(OTA_TASK_NOT_EXISTS);
}
return upgradeTask;
}
}
View on GitHub (pinned to 477be9dd49)
Solutions
- Check the request body: deviceScope must exactly match IotOtaTaskDeviceScopeEnum.SELECT.getScope() or ALL.getScope() — inspect the enum (yudao-module-iot ... enums/ota/IotOtaTaskDeviceScopeEnum) for the literal int values and send one of those.
- If null, make the client always send the field, or add @NotNull on deviceScope in IotOtaTaskCreateReqVO so it fails validation with a clear 400 instead of a 500.
- Replace the IllegalArgumentException with a proper ErrorCodeException (add OTA_TASK_DEVICE_SCOPE_NOT_SUPPORTED to the ErrorCodeConstants and throw exception(...)) so clients receive a structured error.
- If you intended a new scope (e.g. 'specified product'), extend IotOtaTaskDeviceScopeEnum and add a matching branch in validateOtaTaskDeviceScope before the fall-through.
Example fix
// before
throw new IllegalArgumentException("不支持的设备范围:" + createReqVO.getDeviceScope());
// after (structured error code)
throw exception(OTA_TASK_DEVICE_SCOPE_NOT_SUPPORTED, createReqVO.getDeviceScope());
// and on the request VO, reject null early
// @NotNull(message = "设备范围不能为空")
// private Integer deviceScope; Defensive patterns
Strategy: validation
Validate before calling
import cn.iocoder.yudao.module.iot.enums.ota.IotOtaTaskDeviceScopeEnum;
boolean validScope = Arrays.stream(IotOtaTaskDeviceScopeEnum.values())
.map(IotOtaTaskDeviceScopeEnum::getScope)
.anyMatch(s -> Objects.equals(s, createReqVO.getDeviceScope()));
if (!validScope) {
// reject before the service call with a clear message
throw new IllegalArgumentException("deviceScope must be one of "
+ Arrays.toString(IotOtaTaskDeviceScopeEnum.values()));
} Type guard
private static final Set<Integer> SUPPORTED_DEVICE_SCOPES = Arrays.stream(IotOtaTaskDeviceScopeEnum.values())
.map(IotOtaTaskDeviceScopeEnum::getScope)
.collect(Collectors.toSet());
static boolean isSupportedDeviceScope(Integer scope) {
return scope != null && SUPPORTED_DEVICE_SCOPES.contains(scope);
} Try / catch
// Prefer validation over catching: IllegalArgumentException here is a 500-level leak.
// If forced to catch (legacy caller):
try {
otaTaskService.createOtaTask(createReqVO);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("不支持的设备范围")) {
// client sent a bad deviceScope: fix the request payload
} else {
throw e;
}
} Prevention
- Always populate deviceScope from IotOtaTaskDeviceScopeEnum on the client; never hardcode the int.
- Add @NotNull to deviceScope in the VO so nulls fail as 400 validation errors.
- Keep frontend enum constants in sync with backend IotOtaTaskDeviceScopeEnum across version upgrades.
- Test createOtaTask with all enum values plus an invalid one in contract tests to catch drift early.
When it happens
Trigger: Calling createOtaTask / the POST create endpoint with deviceScope set to a value outside {SELECT scope (typically 1), ALL scope (typically 2)} — e.g. 3, 0, a random int, or null (null fails both Objects.equals checks and falls through). It is thrown before any device list is built, right after the firmware/product validation.
Common situations: Frontend sends a new scope value (or a stale enum int) after a version change; hand-written API calls (curl/Postman) with a guessed deviceScope; null deviceScope from a form that never set the field; serialization mismatch (string "1" vs int 1) so the equality check fails.
Related errors
AI-assisted analysis of YunaiV/yudao-cloud@477be9dd49 (2026-08-14).
Data as JSON: /api/errors/1d5d499dc90b144c.
Report an issue: GitHub.