AlistGo/alist · warning

token not active yet

Error message

token not active yet

What it means

ParseToken maps jwt.ValidationErrorNotValidYet to this message: the token's nbf (NotBefore) claim is in the future, so the token is not yet acceptable. Tokens minted by GenerateToken set nbf = now, so this normally indicates clock skew or a manipulated token.

Source

Thrown at server/common/auth.go:55

	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 token
	}
	validTokenCache.Del(tokenString)
	return nil
}

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Sync clocks (NTP/chrony) on all servers that issue or verify tokens
  2. If skew is unavoidable, add validation leeway when calling jwt.ParseWithClaims so small nbf differences are tolerated
  3. Regenerate the token after clocks are corrected

Example fix

// before
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, kf) // no leeway

// after
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, kf,
    jwt.WithLeeway(30*time.Second))
Defensive patterns

Strategy: validation

Validate before calling

if time.Until(time.Unix(claims.NotBefore.Unix(), 0)) > 2*time.Minute {
	// clock skew or forged nbf; reject before JWT parse
}

Try / catch

_, err := common.ParseToken(tok)
if err != nil && strings.Contains(err.Error(), "not active yet") {
	// check NTP sync, then ask client to retry shortly
}

Prevention

When it happens

Trigger: Verifying a token on a server whose clock is behind the issuing server by more than the leeway, or using a hand-crafted token with a future nbf.

Common situations: NTP drift between nodes in multi-instance deployments; container host clock wrong; token generated on a machine with a future clock.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/4a0ab89bbc50d3ad. Report an issue: GitHub.