AlistGo/alist · critical
failed to refresh token: %s
Error message
failed to refresh token: %s
What it means
Thrown when the Dropbox OAuth token endpoint (POST with grant_type=refresh_token) answers with a non-200 status. The response body is included in the message and typically contains error and error_description fields such as invalid_grant or invalid_client. This is a hard authentication configuration failure, not a transient error.
Source
Thrown at drivers/dropbox/util.go:38
url = d.OauthTokenURL
}
var tokenResp TokenResp
resp, err := base.RestyClient.R().
//ForceContentType("application/x-www-form-urlencoded").
//SetBasicAuth(d.ClientID, d.ClientSecret).
SetFormData(map[string]string{
"grant_type": "refresh_token",
"refresh_token": d.RefreshToken,
"client_id": d.ClientID,
"client_secret": d.ClientSecret,
}).
Post(url)
if err != nil {
return err
}
log.Debugf("[dropbox] refresh token response: %s", resp.String())
if resp.StatusCode() != 200 {
return fmt.Errorf("failed to refresh token: %s", resp.String())
}
_ = utils.Json.UnmarshalFromString(resp.String(), &tokenResp)
d.AccessToken = tokenResp.AccessToken
op.MustSaveDriverStorage(d)
return nil
}
func (d *Dropbox) request(uri, method string, callback base.ReqCallback, retry ...bool) ([]byte, error) {
req := base.RestyClient.R()
req.SetHeader("Authorization", "Bearer "+d.AccessToken)
if d.RootNamespaceId != "" {
apiPathRootJson, err := utils.Json.MarshalToString(map[string]interface{}{
".tag": "root",
"root": d.RootNamespaceId,
})
if err != nil {
return nil, err
}View on GitHub (pinned to 843d9dc814)
Solutions
- Read the response body in the message: invalid_grant means generate a NEW refresh token via the OAuth flow; invalid_client means fix ClientID/ClientSecret
- Confirm ClientID and ClientSecret come from the same Dropbox app page that produced the refresh token
- If the app was recreated, repeat the full authorization flow and update all three fields
- After fixing, restart/reload the driver so Init re-runs cleanly
Defensive patterns
Strategy: try-catch
Try / catch
// refreshToken
if err := d.refreshToken(); err != nil {
if strings.Contains(err.Error(), "failed to refresh token") {
// fatal config error: stop retrying and flag storage as needing re-auth
log.Errorf("dropbox refresh token rejected: %s", err)
return err
}
return err // transient network error: safe to retry later
} Prevention
- Treat invalid_grant/invalid_client as permanent — surface to the user instead of retry loops
- Keep client_id, client_secret, and refresh_token from the same Dropbox app in one config unit
- Rotate all three values together whenever the app secret changes
When it happens
Trigger: Expired, revoked, or single-use refresh token (invalid_grant); mismatched client_id/client_secret (invalid_client); the refresh token was issued for a different Dropbox app than the one configured; Dropbox app is disabled.
Common situations: Reusing a refresh token after regenerating the app secret; copying the app key into the secret field; rotating tokens in another tool which invalidated the old one; token issued in production mode used against a development-mode app for an uninvited user.
Related errors
- failed to refresh token: refresh token is empty
- refresh token is empty
- failed to check user: %s
- refresh token failed: %s
- %s : %s
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/ea28eef557eda7fa.
Report an issue: GitHub.