dromara/Sa-Token · error · SaTokenException
CODE_30303
CODE_30303
Error message
token 已超时,无法解析:{jwtToken} What it means
Thrown by SaJwtUtil.getValue when parsing a temp JWT whose embedded effective-time claim (KEY_EFF) is null or in the past (and not the NEVER_EXPIRE sentinel). sa-token temp-jwt tokens are stateless — validity is enforced purely by this embedded timestamp, since there is no server-side record to delete.
Source
Thrown at sa-token-plugin/sa-token-temp-jwt/src/main/java/cn/dev33/satoken/temp/jwt/SaJwtUtil.java:107
.verifyWith(key)
.build()
.parseSignedClaims(jwtToken).getPayload();
}
/**
* 从一个 jwt-token 解析出载荷, 并取出数据
* @param jwtToken JwtToken值
* @param keyt 秘钥
* @return 值
*/
public static Object getValue(String jwtToken, String keyt) {
// 取出数据
Claims claims = parseToken(jwtToken, keyt);
// 验证是否超时
Long eff = claims.get(KEY_EFF, Long.class);
if(eff == null || (eff < System.currentTimeMillis() && eff != NEVER_EXPIRE)) {
throw new SaTokenException("token 已超时,无法解析:" + jwtToken).setCode(SaTempJwtErrorCode.CODE_30303);
}
// 获取数据
return claims.get(KEY_VALUE);
}
/**
* 从一个 jwt-token 解析出载荷, 并取出其剩余有效期
* @param jwtToken JwtToken值
* @param keyt 秘钥
* @return 值
*/
public static long getTimeout(String jwtToken, String keyt) {
// 取出数据
Claims claims = parseToken(jwtToken, keyt);
// 验证是否超时
Long eff = claims.get(KEY_EFF, Long.class);View on GitHub (pinned to ac2c7f6e94)
Solutions
- Re-issue a fresh temp token via SaTempUtil.createToken(value, timeout) when this error occurs
- Issue the token with a longer timeout or SaTempUtil.NEVER_EXPIRE if it must outlive the job
- Sync clocks (NTP) across issuing and validating nodes if tokens expire suspiciously early
Example fix
// before
Object value = SaTempUtil.parseToken(jwtToken, secretKey);
// after — refresh on expiry
Object value;
try {
value = SaJwtUtil.getValue(jwtToken, secretKey);
} catch (SaTokenException e) {
if(SaTempJwtErrorCode.CODE_30303 == e.getCode()) {
jwtToken = SaTempUtil.createToken(originalValue, 60 * 60 * 24);
value = SaJwtUtil.getValue(jwtToken, secretKey);
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
long remain = SaJwtUtil.getTimeout(jwtToken, keyt);
if(remain <= 0) {
// refresh the token before use
} Try / catch
try { SaJwtUtil.getValue(jwtToken, keyt); } catch (SaTokenException e) { if(SaTempJwtErrorCode.CODE_30303 == e.getCode()) { /* re-issue temp token */ } } Prevention
- Choose temp-token timeout from the consumer job's expected duration
- Never treat jwt temp tokens as revocable; design callers to re-issue on expiry
When it happens
Trigger: Calling SaTempTemplateForJwt.getValue(token)/parseToken-based reads on a jwt-temp-token after its effective window elapsed; also fires if the token was created without an eff claim (null).
Common situations: A long-running job holds a temp token issued with a short timeout; server clock skew between issuing and validating machines; using jwt temp tokens as if they were revocable session tokens.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/4ba413fd21196793.
Report an issue: GitHub.