{"record":{"id":"7d78aeaba66a1468","repo":"AlistGo/alist","slug":"s-v-7d78ae","errorCode":null,"errorMessage":"%s: %v","messagePattern":"%s: %v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/google_photo/util.go","lineNumber":69,"sourceCode":"\t}\n\tif resp != nil {\n\t\treq.SetResult(resp)\n\t}\n\tvar e Error\n\treq.SetError(&e)\n\tres, err := req.Execute(method, url)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif e.Error.Code != 0 {\n\t\tif e.Error.Code == 401 {\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(url, method, callback, resp, headers)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%s: %v\", e.Error.Message, e.Error.Errors)\n\t}\n\treturn res.Body(), nil\n}\n\nfunc (d *GooglePhoto) getFiles(id string) ([]MediaItem, error) {\n\tswitch id {\n\tcase FETCH_ALL:\n\t\treturn d.getAllMedias()\n\tcase FETCH_ALBUMS:\n\t\treturn d.getAlbums()\n\tcase FETCH_SHARE_ALBUMS:\n\t\treturn d.getShareAlbums()\n\tcase FETCH_ROOT:\n\t\treturn d.getFakeRoot()\n\tdefault:\n\t\treturn d.getMedias(id)\n\t}\n}","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/google_photo/util.go#L51-L87","documentation":"Generic Google Photos API request error: response parsed as an error object with non-zero code other than 401, returned as '<message>: <errors>'. Covers listing albums, fetching media items, and the upload byte-transfer calls made via d.request with custom upload headers.","triggerScenarios":"Any Photos API call failing structurally: mediaItem not found after deletion, album access revoked, API not enabled, per-minute quota exceeded, invalid pageToken from stale pagination state.","commonSituations":"Cached listing pointing at deleted media; Photos API disabled mid-session; heavy polling hitting 6000 requests/minute/project; token scopes narrowed after re-consent.","solutions":["Act on the reason in '<errors>': not-found -> refresh listings; rate-limit -> backoff; permission -> re-consent with correct scopes","Enable/verify the Photos Library API for the project and its quota","Cache album/media listings briefly and invalidate on 404 reasons","Wrap listing loops with retry-after handling for 403 quota errors"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isPhotosRetryable(err error) bool {\n  return err != nil && strings.Contains(err.Error(), \"Rate\") || strings.Contains(err.Error(), \"backendError\")\n}","tryCatchPattern":"body, err := d.request(url, method, cb, resp, headers)\nif err != nil {\n  if isPhotosRetryable(err) { /* backoff and retry once */ }\n  if strings.Contains(err.Error(), \"No such media\") { /* drop from cache */ }\n}","preventionTips":["Treat 404-class Photos reasons as cache-invalidation signals, not retries","Respect per-minute quotas by caching album and media listings"],"tags":["google-photos","api","quota","permissions"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}