paascloud/paascloud-master · warning · ValidateCodeException
Mobile当天短信发送数上限
Error message
Mobile当天短信发送数上限
What it means
SmsCodeProcessor.checkSendSmsCount enforces per-mobile daily SMS quotas by reading a Redis counter (mobileSmsCountKey, 1-day TTL) and comparing it to sms.getMobileMaxSendCount(). If the counter exceeds the configured mobile daily limit, it throws ValidateCodeException('Mobile当天短信发送数上限'). This is a deliberate anti-abuse throttle to stop a single phone number from exhausting SMS quota or receiving too many codes.
Solutions
- Wait for the 1-day Redis key (mobile SMS count) to expire, or delete the key (e.g. DEL <mobileSmsCountKey>) to reset the quota for testing
- Raise sms.getMobileMaxSendCount() in the security code SMS properties configuration to a value fitting real traffic
- In tests, use different phone numbers per run or flush the Redis counter before each test
- Catch ValidateCodeException in the controller and return a friendly 'daily SMS limit reached, try tomorrow' message
Example fix
// before: repeated test sends hit the limit
smsCodeSender.send(mobile); // throws ValidateCodeException after N sends
// after: reset the counter in test setup
@Test
void setUp() {
redisTemplate.delete("paascloud:sms:count:" + mobile);
} Defensive patterns
Strategy: try-catch
Validate before calling
Integer count = (Integer) redisTemplate.opsForValue().get(mobileSmsCountKey);
if (count != null && count > maxMobileSendCount) {
throw new BizException("SMS daily limit reached for this phone");
} Try / catch
try {
smsCodeSender.send(mobile);
} catch (ValidateCodeException e) {
if (e.getMessage().contains("上限")) {
return Result.error(429, "短信发送次数已达今日上限,请明日再试");
}
throw e;
} Prevention
- Check the mobile's Redis counter before offering the 'send code' UI action and disable the button when at limit
- Configure mobileMaxSendCount realistically for legitimate users (e.g. 10/day), not the minimum
- In CI/integration tests, flush SMS counter keys or use distinct phone numbers per run
- Return HTTP 429 semantics to clients so they can implement backoff
When it happens
Trigger: Calling the SMS send flow (send -> checkSendSmsCount) for a mobile number whose Redis day-counter already exceeds smsProperties.getMobileMaxSendCount(); the counter increments on every send and lives 1 day, so repeated sends to the same phone within 24h trip it.
Common situations: QA/load tests hammering one phone number; users repeatedly requesting codes during login failures; mobileMaxSendCount configured too low in properties for legitimate traffic; integration tests not resetting the Redis counter between runs.
Related errors
AI-assisted analysis of paascloud/paascloud-master@781281a950 (2026-09-10).
Data as JSON: /api/errors/20ae2286ed1a21f1.
Report an issue: GitHub.
Appendix: source
Thrown at paascloud-common/paascloud-security-core/src/main/java/com/paascloud/security/core/validate/code/sms/SmsCodeProcessor.java:116
private void checkSendSmsCount(String mobile, String ipAddr) {
String mobileSmsCountKey = RedisKeyUtil.getSendSmsCountKey(mobile, "mobile");
String ipSmsCountKey = RedisKeyUtil.getSendSmsCountKey(ipAddr, "ip");
String totalSmsCountKey = RedisKeyUtil.getSendSmsCountKey("total", "total");
String sendSmsRateKey = RedisKeyUtil.getSendSmsRateKey(ipAddr);
SmsCodeProperties sms = securityProperties.getCode().getSms();
Integer sendSmsRateCount = (Integer) redisTemplate.opsForValue().get(sendSmsRateKey);
if (sendSmsRateCount != null) {
log.error("操作频率过快 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("操作频率过快");
} else {
redisTemplate.opsForValue().set(sendSmsRateKey, 1, 1, TimeUnit.MINUTES);
}
Integer mobileSmsCount = (Integer) redisTemplate.opsForValue().get(mobileSmsCountKey);
if (mobileSmsCount != null && mobileSmsCount > sms.getMobileMaxSendCount()) {
log.error("Mobile当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("Mobile当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(mobileSmsCountKey, mobileSmsCount == null ? 1 : mobileSmsCount + 1, 1, TimeUnit.DAYS);
}
Integer ipSmsCount = (Integer) redisTemplate.opsForValue().get(ipSmsCountKey);
if (ipSmsCount != null && ipSmsCount > sms.getIpMaxSendCount()) {
log.error("IP当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("IP当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(ipSmsCountKey, ipSmsCount == null ? 1 : ipSmsCount + 1, 1, TimeUnit.DAYS);
}
Integer totalSmsCount = (Integer) redisTemplate.opsForValue().get(totalSmsCountKey);
if (totalSmsCount != null && totalSmsCount > sms.getTotalMaxSendCount()) {
log.error("当天短信发送数上限 ipAddr={}, mobile={}", ipAddr, mobile);
throw new ValidateCodeException("当天短信发送数上限");
} else {
redisTemplate.opsForValue().set(totalSmsCountKey, totalSmsCount == null ? 1 : totalSmsCount + 1, 1, TimeUnit.DAYS);
}
}View on GitHub (pinned to 781281a950)