yikart/AiToEarn · error · UnauthorizedException
Token校验失败,请重新登录
Error message
Token校验失败,请重新登录
What it means
The else branch of decodeToken: any decode error that is NOT TokenExpiredError becomes UnauthorizedException 'Token校验失败,请重新登录'. The token could not be validated/decoded at all — malformed structure, bad signature, or invalid format.
Source
Thrown at project/aitoearn-electron/server/src/auth/auth.service.ts:54
async resetToken(tokenInfo: TokenInfo): Promise<string> {
const payload: TokenInfo = {
phone: tokenInfo.phone,
id: tokenInfo.id,
name: tokenInfo.name,
isManager: tokenInfo.isManager,
};
return this.jwtService.sign(payload);
}
async decodeToken(token: string): Promise<TokenInfo> {
token = token.replace('Bearer ', '');
try {
return this.jwtService.decode(token);
} catch (error) {
if (error.name === 'TokenExpiredError') {
throw new UnauthorizedException('Token已过期,请重新登录');
} else {
throw new UnauthorizedException('Token校验失败,请重新登录');
}
}
}
}
View on GitHub (pinned to d3aa8bea5b)
Solutions
- Re-login to get a fresh, correctly signed token.
- Confirm AUTH_SECRET is identical across server instances/environments.
- Inspect the Authorization header format: must be 'Bearer <jwt>'.
- Decode the token at jwt.io to check its structure and signature.
Example fix
// before
const token = localStorage.getItem('token');
// after
const token = localStorage.getItem('token');
if (!token || token.split('.').length !== 3) await relogin(); Defensive patterns
Strategy: try-catch
Validate before calling
function isWellFormedJwt(token) {
const t = token.replace(/^Bearer\s+/, '');
return typeof t === 'string' && t.split('.').length === 3 && t.length > 20;
} Type guard
function hasJwtShape(t) {
return typeof t === 'string' && t.split('.').length === 3;
} Try / catch
try {
await api.call(token);
} catch (e) {
if (e?.response?.status === 401 && /Token校验失败/.test(e.message)) {
await relogin(); // token 结构/签名无效,必须重新登录
} else throw e;
} Prevention
- Never hand-edit or truncate tokens; re-login instead.
- Ensure AUTH_SECRET matches across environments before switching servers.
- Always send the 'Bearer ' prefix exactly once.
- On 401 with this message, re-login rather than retrying with the same token.
When it happens
Trigger: Requests with a corrupted/truncated JWT, a token signed with a different AUTH_SECRET, garbage in the Authorization header after 'Bearer ', or a JsonWebTokenError during decode.
Common situations: Secret rotation between server deploys invalidating old tokens; client sending a raw token without 'Bearer ' handled correctly; token copied from another environment; AUTH_SECRET differing between instances.
Related errors
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/aa7f2e031eda8fbf.
Report an issue: GitHub.