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

  1. Guard with isLogin() (or checkLogin()) before calling StpUtil.getSession() / getSessionByLoginId in request-scoped code.
  2. If the loginId originates from user input or a nullable field, validate it is non-empty before the call.
  3. In background threads, pass the loginId explicitly from the originating request instead of relying on context.
  4. 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

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.