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

  1. Generate a new authorization code and complete the exchange immediately (codes are single-use and short-lived).
  2. Verify the Dropbox app's AppKey/AppSecret stored in d.Addition match the current app in the Dropbox App Console.
  3. Confirm redirect_uri is exactly 'https://cloudoauth.files.casaos.app' both here and in the app console.
  4. 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

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.