dromara/Sa-Token · warning · RuntimeException

设备id或用户id不能为空

Error message

设备id或用户id不能为空

What it means

Demo utility in sa-token-demo-device-lock (device-binding example). setDeviceIdToUserId persists a deviceId -> userId mapping with a 1200-second TTL and requires both arguments to be non-empty; an empty deviceId (or the always-non-empty long check failing on userId==0, since SaFoxUtil.isEmpty(long) boxes to Long and only 0/empty triggers) throws RuntimeException. It is sample code, not part of the library.

Source

Thrown at sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java:20

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.util.SaFoxUtil;

/**
 * 设备锁操作工具类
 * @author click33
 * @since 2025/3/5
 */
public class DeviceLockCheckUtil {

    /**
     * 保存设备id与用户id的映射关系
     * @param deviceId /
     * @param userId /
     */
    public static void setDeviceIdToUserId(String deviceId, long userId) {
        if(SaFoxUtil.isEmpty(deviceId) || SaFoxUtil.isEmpty(userId)) {
            throw new RuntimeException("设备id或用户id不能为空");
        }
        SaManager.getSaTokenDao().set(saveKeyPrefix() + deviceId, String.valueOf(userId), 1200);
    }

    /**
     * 返回设备id绑定的用户id
     * @param deviceId /
     */
    public static long getUserIdByDeviceId(String deviceId) {
        String userIdStr = SaManager.getSaTokenDao().get(saveKeyPrefix() + deviceId);
        if(userIdStr == null) {
            throw new RuntimeException("此设备id目前未绑定任何用户");
        }
        return Long.parseLong(userIdStr);
    }

    // 返回数据保存时使用的前缀
    public static Object saveKeyPrefix() {

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Ensure the client submits a non-empty deviceId (usually a header set by the app/mini-program) before calling setDeviceIdToUserId
  2. Guard the call: if (SaFoxUtil.isEmpty(deviceId) || userId <= 0) return error to the caller instead of throwing
  3. If you adapted this code, change SaFoxUtil.isEmpty(userId) to userId <= 0 so legitimate id 0 is not rejected

Example fix

// before
DeviceLockCheckUtil.setDeviceIdToUserId(requestDeviceId, userId); // null device id

// after
if (SaFoxUtil.isEmpty(requestDeviceId) || userId <= 0) {
    throw new SaTokenException("请提交有效的设备id与用户id");
}
DeviceLockCheckUtil.setDeviceIdToUserId(requestDeviceId, userId);
Defensive patterns

Strategy: validation

Validate before calling

if (SaFoxUtil.isEmpty(deviceId) || userId <= 0) {
    // return a 400 to the client; do not call setDeviceIdToUserId
}

Type guard

public static boolean isValidDeviceBinding(String deviceId, long userId) {
    return deviceId != null && !deviceId.trim().isEmpty() && userId > 0;
}

Prevention

When it happens

Trigger: Calling DeviceLockCheckUtil.setDeviceIdToUserId(deviceId, userId) with deviceId null/empty/whitespace, or userId == 0 (SaFoxUtil.isEmpty treats boxed 0 as empty).

Common situations: Frontend not sending the device-id header/param so the controller passes null; using userId 0 as a sentinel; adapting the demo and keeping the isEmpty(long) guard which wrongly rejects id 0.

Related errors


AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14). Data as JSON: /api/errors/9a5c72bd172d4169. Report an issue: GitHub.