{"record":{"id":"e4c4764a458d22d1","repo":"AlistGo/alist","slug":"s-s-e4c476","errorCode":null,"errorMessage":"%s:%s","messagePattern":"%s:%s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/dropbox/util.go","lineNumber":85,"sourceCode":"\tres, err := req.Execute(method, d.base+uri)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlog.Debugf(\"[dropbox] request (%s) response: %s\", uri, res.String())\n\tisRetry := len(retry) > 0 && retry[0]\n\tif res.StatusCode() != 200 {\n\t\tbody := res.String()\n\t\tif !isRetry && (utils.SliceMeet([]string{\"expired_access_token\", \"invalid_access_token\", \"authorization\"}, body,\n\t\t\tfunc(item string, v string) bool {\n\t\t\t\treturn strings.Contains(v, item)\n\t\t\t}) || d.AccessToken == \"\") {\n\t\t\terr = d.refreshToken()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn d.request(uri, method, callback, true)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s:%s\", e.Error, e.ErrorSummary)\n\t}\n\treturn res.Body(), nil\n}\n\nfunc (d *Dropbox) list(ctx context.Context, data base.Json, isContinue bool) (*ListResp, error) {\n\tvar resp ListResp\n\turi := \"/2/files/list_folder\"\n\tif isContinue {\n\t\turi += \"/continue\"\n\t}\n\t_, err := d.request(uri, http.MethodPost, func(req *resty.Request) {\n\t\treq.SetContext(ctx).SetBody(data).SetResult(&resp)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &resp, nil\n}","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/dropbox/util.go#L67-L103","documentation":"This is Dropbox driver's generic API error formatter: the request returned non-200, it was not an auth error (or a token refresh was already retried), so it surfaces the parsed Dropbox error tag and error_summary joined as \"tag: summary\". The two fields come from Dropbox's v2 error JSON, where Error is the short tag (e.g. path/conflict) and ErrorSummary the human-readable detail.","triggerScenarios":"Any non-auth Dropbox API failure after the single retry-on-refresh: 400 from malformed parameters, 409 path_lookup/not_found or path/conflict on file operations, 429 rate limiting (too_many_requests), 403 from insufficient app permissions (e.g. missing files.metadata.read scope).","commonSituations":"Missing OAuth scopes for the operation attempted (app has files.content.read but driver tries a write); operating on a file/folder that was moved or deleted; hammering the API and hitting rate limits; accessing team content without the team scopes.","solutions":["Decode the error_summary in the message — it names the exact problem (e.g. missing_scope tells you which scope to add in the App Console)","For missing_scope: add the scope in the Dropbox App Console and re-authorize to get a new refresh token","For too_many_requests/rate_limit: back off and retry with exponential delay","For path errors: re-list the parent to refresh ids/paths before retrying the operation"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"_, err := d.request(uri, method, cb)\nif err != nil {\n    if strings.Contains(err.Error(), \"too_many_requests\") || strings.Contains(err.Error(), \"rate_limit\") {\n        time.Sleep(backoff.Next()) // exponential backoff, then retry\n        return d.request(uri, method, cb)\n    }\n    if strings.Contains(err.Error(), \"missing_scope\") {\n        return fmt.Errorf(\"dropbox app lacks scope; update App Console: %w\", err)\n    }\n    return err\n}","preventionTips":["Match app scopes to every driver operation (read AND write scopes for two-way mounts)","Cache listings to stay under Dropbox rate limits","Handle 409 path errors by refreshing path state rather than blind retries"],"tags":["dropbox","api","rate-limit","scopes"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}