AlistGo/alist · error
that's not even a token
Error message
that's not even a token
What it means
ParseToken maps jwt.ValidationErrorMalformed to this message: the string is not a well-formed JWT at all — it could not be parsed into three dot-separated base64 segments with valid structure.
Source
Thrown at server/common/auth.go:51
tokenString, err = token.SignedString(SecretKey)
if err != nil {
return "", err
}
validTokenCache.Set(tokenString, true)
return tokenString, err
}
func ParseToken(tokenString string) (*UserClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return SecretKey, nil
})
if IsTokenInvalidated(tokenString) {
return nil, errors.New("token is invalidated")
}
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, errors.New("that's not even a token")
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
return nil, errors.New("token is expired")
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, errors.New("token not active yet")
} else {
return nil, errors.New("couldn't handle this token")
}
}
}
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("couldn't handle this token")
}
func InvalidateToken(tokenString string) error {
if tokenString == "" {
return nil // don't invalidate empty guest tokenView on GitHub (pinned to 843d9dc814)
Solutions
- Ensure the client sends a JWT issued by /api/auth/login in the Authorization header
- Split the header correctly (strip the "Bearer " prefix, handle case) before calling ParseToken
- Validate shape first: token must have 3 dot-separated, non-empty segments
Example fix
// before
tokenString := strings.TrimPrefix(authHeader, "bearer ") // wrong case handling left 'Bearer '
// after
parts := strings.SplitN(authHeader, " ", 2)
if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") {
return errors.New("malformed authorization header")
}
tokenString := parts[1] Defensive patterns
Strategy: validation
Validate before calling
func looksLikeJWT(s string) bool {
p := strings.Split(s, ".")
return len(p) == 3 && p[0] != "" && p[1] != "" && p[2] != ""
} Type guard
func isJWT(s string) bool { return looksLikeJWT(s) } Try / catch
_, err := common.ParseToken(tok)
if err != nil && strings.Contains(err.Error(), "not even a token") {
// reject the credential outright; do not retry
} Prevention
- Parse the Authorization header strictly (Bearer scheme, case-insensitive)
- Shape-check tokens before hitting the JWT parser
When it happens
Trigger: Passing "abc", a base64 blob without dots, a truncated token, or a non-JWT string (e.g. a raw API key or sign string) to ParseToken.
Common situations: Authorization header parsing bug that passes "Bearer" without the token; client sends the wrong credential type; token mangled by a proxy or copy/paste truncation.
Related errors
- token is invalidated
- token is expired
- token not active yet
- couldn't handle this token
- failed to refresh token: sub not match
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/64cbe51f0165af62.
Report an issue: GitHub.