IceWhaleTech/CasaOS · error
e.Error
Error message
e.Error
What it means
During the Dropbox OAuth authorization-code exchange, the token endpoint responded with an error payload (TokenError.Error non-empty). The driver wraps that raw error string with fmt.Errorf(e.Error) — a non-constant format string — and returns it. Typical underlying values are 'invalid_grant' or 'invalid_client'.
Source
Thrown at drivers/dropbox/util.go:34
)
func (d *Dropbox) getRefreshToken() error {
url := "https://api.dropbox.com/oauth2/token"
var resp base.TokenResp
var e TokenError
res, err := base.RestyClient.R().SetResult(&resp).SetError(&e).
SetFormData(map[string]string{
"code": d.Code,
"grant_type": "authorization_code",
"redirect_uri": "https://cloudoauth.files.casaos.app",
}).SetBasicAuth(d.Addition.AppKey, d.Addition.AppSecret).SetHeader("Content-Type", "application/x-www-form-urlencoded").Post(url)
if err != nil {
return err
}
logger.Info("get refresh token", zap.String("res", res.String()))
if e.Error != "" {
return fmt.Errorf(e.Error)
}
d.RefreshToken = resp.RefreshToken
return nil
}
func (d *Dropbox) refreshToken() error {
url := "https://api.dropbox.com/oauth2/token"
var resp base.TokenResp
var e TokenError
res, err := base.RestyClient.R().SetResult(&resp).SetError(&e).
SetFormData(map[string]string{
"refresh_token": d.RefreshToken,
"grant_type": "refresh_token",
}).SetBasicAuth(d.Addition.AppKey, d.Addition.AppSecret).SetHeader("Content-Type", "application/x-www-form-urlencoded").Post(url)
if err != nil {
return err
}View on GitHub (pinned to 0d3b2f444e)
Solutions
- Generate a new authorization code and complete the exchange immediately (codes are single-use and short-lived).
- Verify the Dropbox app's AppKey/AppSecret stored in d.Addition match the current app in the Dropbox App Console.
- Confirm redirect_uri is exactly 'https://cloudoauth.files.casaos.app' both here and in the app console.
- Check the logged response body (logger.Info "get refresh token") for the exact error_description.
Example fix
// before (non-constant format string — also a govet printf issue) return fmt.Errorf(e.Error) // after return errors.New(e.Error)
Defensive patterns
Strategy: validation
Validate before calling
if d.Addition.AppKey == "" || d.Addition.AppSecret == "" {
return errors.New("Dropbox AppKey/AppSecret must be configured before OAuth")
} Try / catch
if err := d.getRefreshToken(); err != nil {
if strings.Contains(err.Error(), "invalid_grant") {
// code expired/used: discard it and re-run the consent flow; never retry same code
}
return err
} Prevention
- Treat authorization codes as single-use and time-limited: fetch and exchange in one step
- Keep AppKey/AppSecret in config validated at driver init
- Register the exact redirect URI in the Dropbox console before deploying
When it happens
Trigger: Exchanging d.Code for a refresh token when the code is expired/already used, when the AppKey/AppSecret basic-auth credentials are wrong, or when the redirect_uri does not match the one used at authorization.
Common situations: User pasted an authorization code after it expired (~10 min) or re-did the flow; Dropbox app key/secret rotated; the 'cloudoauth.files.casaos.app' redirect was altered; clock skew or copying the code with whitespace.
Related errors
AI-assisted analysis of IceWhaleTech/CasaOS@0d3b2f444e (2026-08-15).
Data as JSON: /api/errors/d044d7d0c3dd7e57.
Report an issue: GitHub.