dromara/Sa-Token · error · SaTokenException
Account-Session 获取失败:loginId 不能为空
Error message
Account-Session 获取失败:loginId 不能为空
What it means
Thrown by StpLogic.getSessionByLoginId when loginId is null or empty. The Account-Session key is derived from loginId (satoken:login:session:{loginType}:{loginId}), so an empty id cannot map to any session. It is a defensive guard against programmer error, not a runtime state problem.
Source
Thrown at sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java:1428
*
* @param sessionId SessionId
* @return Session对象
*/
public SaSession getSessionBySessionId(String sessionId) {
return getSessionBySessionId(sessionId, false, null, null);
}
/**
* 获取指定账号 id 的 Account-Session, 如果该 SaSession 尚未创建,isCreate=是否新建并返回
*
* @param loginId 账号id
* @param isCreate 是否新建
* @param timeout 如果这个 SaSession 是新建的,则使用此值作为过期值(单位:秒),可填 null,代表使用全局 timeout 值
* @return SaSession 对象
*/
public SaSession getSessionByLoginId(Object loginId, boolean isCreate, Long timeout) {
if(SaFoxUtil.isEmpty(loginId)) {
throw new SaTokenException("Account-Session 获取失败:loginId 不能为空");
}
return getSessionBySessionId(splicingKeySession(loginId), isCreate, timeout, session -> {
// 这里是该 Account-Session 首次创建时才会被执行的方法:
// 设定这个 SaSession 的各种基础信息:类型、账号体系、账号id
session.setType(SaTokenConsts.SESSION_TYPE__ACCOUNT);
session.setLoginType(getLoginType());
session.setLoginId(loginId);
});
}
/**
* 获取指定账号 id 的 Account-Session, 如果该 SaSession 尚未创建,isCreate=是否新建并返回
*
* @param loginId 账号id
* @param isCreate 是否新建
* @return SaSession 对象
*/
public SaSession getSessionByLoginId(Object loginId, boolean isCreate) {View on GitHub (pinned to ac2c7f6e94)
Solutions
- Guard with isLogin() (or checkLogin()) before calling StpUtil.getSession() / getSessionByLoginId in request-scoped code.
- If the loginId originates from user input or a nullable field, validate it is non-empty before the call.
- In background threads, pass the loginId explicitly from the originating request instead of relying on context.
- Verify the token configuration (token-name, token-prefix, is-read-cookie/header) so the loginId can actually be resolved.
Example fix
// before
SaSession session = StpUtil.getSessionByLoginId(userId, true);
// after
if (SaFoxUtil.isEmpty(userId)) {
throw new IllegalArgumentException("userId required");
}
SaSession session = StpUtil.getSessionByLoginId(userId, true); Defensive patterns
Strategy: validation
Validate before calling
StpUtil.checkLogin(); // guarantees a resolvable loginId in request context SaSession s = StpUtil.getSession();
Type guard
Object loginId = StpUtil.getLoginIdDefaultNull(); boolean hasLoginId = loginId != null && !String.valueOf(loginId).isEmpty();
Prevention
- Guard session access behind login checks
- Pass explicit loginIds into background jobs instead of relying on request context
- Validate nullable user ids at the controller boundary
When it happens
Trigger: Calling getSessionByLoginId(null, ...) or getSessionByLoginId("", ...) — often indirectly via StpUtil.getSession() when not logged in and getLoginId() returned null, or via getSessionByLoginId(request.getParameter("uid")) with a missing parameter.
Common situations: Invoking StpUtil.getSession() in a route not guarded by login check; passing a numeric id that was never set (Long null unboxed/unprinted as 'null'); session-related code run in async threads where the request context is absent.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/0db429799ff91108.
Report an issue: GitHub.