dromara/Sa-Token · error · SaSignException
CODE_12203
CODE_12203
Error message
timestamp 超出允许的范围:{timestamp} What it means
Thrown by SaSignTemplate.checkTimestamp when |now - timestamp| exceeds the configured timestampDisparity and disparity is not -1 (unlimited) — code 12203. Server-side API signing includes a freshness window to block replay of intercepted signed requests; a timestamp outside the window is rejected before nonce/sign are even evaluated.
Source
Thrown at sa-token-plugin/sa-token-sign/src/main/java/cn/dev33/satoken/sign/template/SaSignTemplate.java:241
/**
* 判断:指定时间戳与当前时间戳的差距是否在允许的范围内
* @param timestamp 待校验的时间戳
* @return 是否在允许的范围内
*/
public boolean isValidTimestamp(long timestamp) {
long allowDisparity = getSignConfigOrGlobal().getTimestampDisparity();
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
return allowDisparity == -1 || disparity <= allowDisparity;
}
/**
* 校验:指定时间戳与当前时间戳的差距是否在允许的范围内,如果超出则抛出异常
* @param timestamp 待校验的时间戳
*/
public void checkTimestamp(long timestamp) {
if( ! isValidTimestamp(timestamp) ) {
throw new SaSignException("timestamp 超出允许的范围:" + timestamp).setCode(SaSignErrorCode.CODE_12203);
}
}
/**
* 判断:随机字符串 nonce 是否有效。
* 注意:同一 nonce 可以被多次判断有效,不会被缓存
* @param nonce 待判断的随机字符串
* @return 是否有效
*/
public boolean isValidNonce(String nonce) {
// 为空代表无效
if(SaFoxUtil.isEmpty(nonce)) {
return false;
}
// 校验此 nonce 是否已被使用过
String key = splicingNonceSaveKey(nonce);
return SaManager.getSaTokenDao().get(key) == null;View on GitHub (pinned to ac2c7f6e94)
Solutions
- Sync server clocks (NTP/chrony) on both signing and verifying machines
- Generate the timestamp at request time in milliseconds (System.currentTimeMillis()), never cache or reuse it
- Widen sa-token sign timestamp-disparity config if legitimate latency exceeds the window, or set -1 only if you accept replay risk mitigated by nonce
Example fix
// before
params.put("timestamp", "1609459200000"); // fixed/old timestamp
// after
params.put("timestamp", String.valueOf(System.currentTimeMillis())); Defensive patterns
Strategy: validation
Validate before calling
long disparity = Math.abs(System.currentTimeMillis() - timestamp);
if (disparity > signConfig.getTimestampDisparity()) throw new IllegalArgumentException("timestamp stale by " + disparity + " ms"); Try / catch
try { saSignTemplate.checkTimestamp(ts); } catch (SaSignException e) { if (e.getCode() == 12203) return status(401, "timestamp out of range — check clock sync"); throw e; } Prevention
- Run NTP on all app servers and use System.currentTimeMillis() at signing time
- Monitor clock skew between services; alert before it approaches timestampDisparity
When it happens
Trigger: Sending a signed request whose timestamp parameter deviates from server time by more than timestampDisparity milliseconds (default window, commonly 15 min), including stale timestamps from cached/retried requests.
Common situations: Client machine clock drift or wrong timezone-epoch handling (seconds vs milliseconds); NTP not running on app servers; requests queued/retried long after signing; disparity configured very tightly.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/5f73d07388f8cec2.
Report an issue: GitHub.