yikart/AiToEarn · error · AppHttpException
ErrHttpBack.err_user_code_send_fail
ErrHttpBack.err_user_code_send_fail
Error message
err_user_code_send_fail
What it means
AppHttpException with ErrHttpBack.err_user_code_send_fail (errCode 40020, message '验证码发送失败'). Thrown by LoginService.postPhoneRegisterCode (login.service.ts:40) when NODE_ENV=production and alicloudSmsService.sendLoginSms returns a falsy result, meaning AliCloud SMS failed to send the code. In non-production the SMS call result is not enforced (the code is returned directly).
Source
Thrown at project/aitoearn-electron/server/src/user/login.service.ts:40
constructor(
private readonly redisService: RedisService,
private readonly alicloudSmsService: AlicloudSmsService,
) {}
/**
* 发送手机号注册的验证码
* @param phone
*/
async postPhoneRegisterCode(phone: string) {
const cacheKey = `${LoginTypeCacheKey.Password}:${phone}`;
let code = await this.redisService.get(cacheKey);
if (code) throw new AppHttpException(ErrHttpBack.err_user_code_had);
code = getRandomString(6, true);
const res = await this.alicloudSmsService.sendLoginSms(phone, code);
if (process.env.NODE_ENV === 'production') {
if (!res) throw new AppHttpException(ErrHttpBack.err_user_code_send_fail);
}
this.redisService.setKey(cacheKey, code, 60 * 5);
console.log('发送短信成功', code);
return process.env.NODE_ENV === 'production' ? res : code;
}
/**
* 发送手机号登录的验证码
* @param phone
*/
async postPhoneLoginCode(phone: string) {
const cacheKey = `${LoginTypeCacheKey.Code}:${phone}`;
let code = await this.redisService.get(cacheKey);
if (code) throw new AppHttpException(ErrHttpBack.err_user_code_had);
code = getRandomString(6, true);View on GitHub (pinned to d3aa8bea5b)
Solutions
- Check AliCloud SMS credentials and configuration (access key, signature, template id) in the production env
- Inspect the AliCloud SMS API response/logs for the reject reason (throttle, invalid phone, blacklisted)
- Verify the SMS account has balance and the template/signature are approved
- Only set NODE_ENV=production after SMS is verified working, since enforcement only happens in production
Example fix
// env // before ALICLOUD_SMS_TEMPLATE=unset // after ALICLOUD_ACCESS_KEY=xxx ALICLOUD_SMS_SIGN=AiToEarn ALICLOUD_SMS_TEMPLATE=SMS_123456789
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: verify SMS config is reachable before user flows
const cfgOk = !!(process.env.ALICLOUD_ACCESS_KEY && process.env.ALICLOUD_SMS_SIGN && process.env.ALICLOUD_SMS_TEMPLATE)
if (!cfgOk) throw new Error('AliCloud SMS configuration missing') Type guard
function isSmsConfigured(cfg: Partial<SmsConfig>): cfg is SmsConfig {
return Boolean(cfg.accessKey && cfg.sign && cfg.templateCode)
} Try / catch
try {
await api.postPhoneRegisterCode(phone)
} catch (e) {
if (e?.errCode === '40020') {
// log SMS failure details, surface a retry-with-backoff message to the user
} else throw e
} Prevention
- Validate AliCloud SMS credentials, signature and template at service startup
- Monitor SMS account balance and provider error rates
- Test sendLoginSms in a staging environment with production-like credentials before release
When it happens
Trigger: Requesting a register SMS code in a production deployment where alicloudSmsService.sendLoginSms(phone, code) resolves to null/false — SMS provider rejects or fails the send.
Common situations: Missing or invalid AliCloud SMS credentials (accessKeyId/secret, sign name, template code); phone number rejected (invalid format, blacklist, throttling by AliCloud); SMS account balance exhausted or template not approved for the region.
Related errors
- InvalidModel
- InvalidModel
- image aspectRatio cannot be converted to a supported size
- ResponseCode.ChannelAccountCreateNotSupported
- ChannelAuthorizationFailed
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/61399e7f7773a055.
Report an issue: GitHub.