AlistGo/alist · error
%s : %s
Error message
%s : %s
What it means
Thrown by YandexDisk's token refresh in util.go when the OAuth token endpoint response parses into the error envelope (e.Error non-empty). The refresh_token grant failed, so no new AccessToken is obtained and every subsequent request would use stale credentials. Format is "<error> : <error_description>" straight from Yandex OAuth.
Source
Thrown at drivers/yandex_disk/util.go:30
)
// do others that not defined in Driver interface
func (d *YandexDisk) refreshToken() error {
u := "https://oauth.yandex.com/token"
var resp base.TokenResp
var e TokenErrResp
_, err := base.RestyClient.R().SetResult(&resp).SetError(&e).SetFormData(map[string]string{
"grant_type": "refresh_token",
"refresh_token": d.RefreshToken,
"client_id": d.ClientID,
"client_secret": d.ClientSecret,
}).Post(u)
if err != nil {
return err
}
if e.Error != "" {
return fmt.Errorf("%s : %s", e.Error, e.ErrorDescription)
}
d.AccessToken, d.RefreshToken = resp.AccessToken, resp.RefreshToken
op.MustSaveDriverStorage(d)
return nil
}
func (d *YandexDisk) request(pathname string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
u := "https://cloud-api.yandex.net/v1/disk/resources" + pathname
req := base.RestyClient.R()
req.SetHeader("Authorization", "OAuth "+d.AccessToken)
if callback != nil {
callback(req)
}
if resp != nil {
req.SetResult(resp)
}
var e ErrResp
req.SetError(&e)View on GitHub (pinned to 843d9dc814)
Solutions
- Re-run the OAuth authorization flow to obtain a fresh refresh token and save driver storage
- Verify ClientID and ClientSecret in driver config match the registered Yandex OAuth app
- Confirm RefreshToken is non-empty and was stored completely (no truncation)
- If error is invalid_grant due to rate limiting, wait and retry refresh rather than re-authorizing
Example fix
// before
if e.Error != "" {
return fmt.Errorf("%s : %s", e.Error, e.ErrorDescription)
}
// after
if e.Error != "" {
if e.Error == "invalid_grant" {
return fmt.Errorf("yandex disk: refresh token expired/revoked, re-authorization required: %s : %s", e.Error, e.ErrorDescription)
}
return fmt.Errorf("%s : %s", e.Error, e.ErrorDescription)
} Defensive patterns
Strategy: try-catch
Validate before calling
if strings.TrimSpace(d.RefreshToken) == "" || strings.TrimSpace(d.ClientID) == "" || strings.TrimSpace(d.ClientSecret) == "" {
return errors.New("yandex disk: oauth config incomplete (refresh_token/client_id/client_secret)")
} Try / catch
if err := d.refreshToken(); err != nil {
if strings.Contains(err.Error(), "invalid_grant") {
return fmt.Errorf("yandex disk: re-authorization required (refresh token revoked/expired): %w", err)
}
return err // transient (rate limit/network): retry later without re-auth
} Prevention
- Surface invalid_grant as 're-login required' instead of a generic error
- Persist the rotated RefreshToken immediately after each refresh (the code already does MustSaveDriverStorage)
- Never copy driver storage between instances — refresh tokens are single-use in rotation
When it happens
Trigger: Refresh token revoked or expired (Yandex refresh tokens can be invalidated after a year or by re-authorization); wrong client_id/client_secret pair; user changed account password; the stored RefreshToken is empty or was truncated.
Common situations: Long-lived deployment where nobody re-authorized for months; copying driver storage between instances causing token reuse; Yandex OAuth app settings changed (client secret rotated); rate limiting returning invalid_grant.
Related errors
- failed to refresh token: refresh token is empty
- refresh token is empty
- failed to refresh token: %s
- refresh token failed: %s
- not a jwt token because of invalid segments
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/504ad790d31bf8ac.
Report an issue: GitHub.