{"record":{"id":"b2cf16ffb01777a4","repo":"dromara/Sa-Token","slug":"token-session-token","errorCode":null,"errorMessage":"Token-Session 获取失败：token 不能为空","messagePattern":"Token-Session 获取失败：token 不能为空","errorType":"validation","errorClass":"SaTokenException","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java","lineNumber":225,"sourceCode":" \t */\n\t@Override\n \tpublic long getTokenTimeout(String tokenValue) {\n \t\treturn SaJwtUtil.getTimeout(tokenValue, loginType, jwtSecretKey());\n \t}\n\n\n\t// ------------------- Token-Session 相关 -------------------\n\n\t/**\n\t * 获取指定 token 的 Token-Session，如果该 SaSession 尚未创建，isCreate代表是否新建并返回\n\t *\n\t * @param tokenValue token值\n\t * @param isCreate 是否新建\n\t * @return session对象\n\t */\n\tpublic SaSession getTokenSessionByToken(String tokenValue, boolean isCreate) {\n\t\tif(SaFoxUtil.isEmpty(tokenValue)) {\n\t\t\tthrow new SaTokenException(\"Token-Session 获取失败：token 不能为空\");\n\t\t}\n\t\tlong timeout = getTokenTimeout(tokenValue);\n\t\treturn getSessionBySessionId(splicingKeyTokenSession(tokenValue), isCreate, timeout, session -> {\n\t\t\t// 这里是该 Token-Session 首次创建时才会被执行的方法：\n\t\t\t// \t\t设定这个 SaSession 的各种基础信息：类型、账号体系、Token 值\n\t\t\tsession.setType(SaTokenConsts.SESSION_TYPE__TOKEN);\n\t\t\tsession.setLoginType(getLoginType());\n\t\t\tsession.setToken(tokenValue);\n\t\t});\n\t}\n\n\n\t// ------------------- 会话管理 -------------------  \n\n\t/**\n\t * [禁用] 根据条件查询Token \n\t */\n\t@Override","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-jwt/src/main/java/cn/dev33/satoken/jwt/StpLogicJwtForMixin.java#L207-L243","documentation":"Thrown by StpLogicJwtForMixin.getTokenSessionByToken when tokenValue is empty. In JWT Mixin mode, Token-Session data is still stored server-side keyed by the token string, so an empty token cannot address a session. No dedicated code is set (generic SaTokenException).","triggerScenarios":"Calling getTokenSession()/getTokenSessionByToken() (JWT Mixin mode) when the request contains no token — e.g. StpUtil.getTokenValue() returned an empty string and was passed through.","commonSituations":"Endpoint annotated to allow anonymous access still calls getTokenSession(); token read from a cookie/header that is absent; frontend first request before login obtains a token.","solutions":["Only call getTokenSession() after ensuring a token is present (StpUtil.getTokenValue() non-empty)","Guard anonymous-permitted handlers: skip session access or check StpUtil.isLogin() first","Send the token in the style your config reads (header/cookie/param) on every request"],"exampleFix":"// before\nSaSession s = StpUtil.getTokenSession(); // no token in request -> throws\n\n// after\nString token = StpUtil.getTokenValue();\nif (SaFoxUtil.isNotEmpty(token)) {\n    SaSession s = StpUtil.getTokenSession();\n    // ...\n} else {\n    // anonymous path\n}","handlingStrategy":"validation","validationCode":"String token = StpUtil.getTokenValue();\nif (SaFoxUtil.isEmpty(token)) {\n    // anonymous request: skip Token-Session usage\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call getTokenSession() only on authenticated routes or after an isLogin() check","Ensure the frontend sends the token in the configured token-name/style for every stateful request"],"tags":["sa-token","jwt","session","empty-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}