{"record":{"id":"ff88036dda97de0f","repo":"IceWhaleTech/CasaOS","slug":"e-error-ff8803","errorCode":null,"errorMessage":"e.Error","messagePattern":"e\\.Error","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/google_drive/util.go","lineNumber":43,"sourceCode":"\nfunc (d *GoogleDrive) getRefreshToken() error {\n\turl := \"https://www.googleapis.com/oauth2/v4/token\"\n\tvar resp base.TokenResp\n\tvar e TokenError\n\tres, err := base.RestyClient.R().SetResult(&resp).SetError(&e).\n\t\tSetFormData(map[string]string{\n\t\t\t\"client_id\":     d.ClientID,\n\t\t\t\"client_secret\": d.ClientSecret,\n\t\t\t\"code\":          d.Code,\n\t\t\t\"grant_type\":    \"authorization_code\",\n\t\t\t\"redirect_uri\":  \"https://cloudoauth.files.casaos.app\",\n\t\t}).Post(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlogger.Info(\"get refresh token\", zap.String(\"res\", res.String()))\n\tif e.Error != \"\" {\n\t\treturn fmt.Errorf(e.Error)\n\t}\n\td.RefreshToken = resp.RefreshToken\n\treturn nil\n}\n\nfunc (d *GoogleDrive) refreshToken() error {\n\turl := \"https://www.googleapis.com/oauth2/v4/token\"\n\tvar resp base.TokenResp\n\tvar e TokenError\n\tres, err := base.RestyClient.R().SetResult(&resp).SetError(&e).\n\t\tSetFormData(map[string]string{\n\t\t\t\"client_id\":     d.ClientID,\n\t\t\t\"client_secret\": d.ClientSecret,\n\t\t\t\"refresh_token\": d.RefreshToken,\n\t\t\t\"grant_type\":    \"refresh_token\",\n\t\t}).Post(url)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/IceWhaleTech/CasaOS/blob/0d3b2f444ec0193193cf03eef6d43c6e35b0183e/drivers/google_drive/util.go#L25-L61","documentation":"During the Google Drive OAuth authorization-code exchange, the token endpoint responded with an error payload (TokenError.Error non-empty). The raw error string (typically 'invalid_grant' or 'redirect_uri_mismatch') is used as a fmt.Errorf format string and returned.","triggerScenarios":"Exchanging d.Code when it is expired, already redeemed, or was issued for a different client_id/redirect_uri; wrong ClientID/ClientSecret in the driver config.","commonSituations":"Authorization code older than ~10 minutes or reused after a failed attempt; redirect_uri differs from the registered 'https://cloudoauth.files.casaos.app'; credentials from a different Google Cloud project.","solutions":["Start the OAuth flow again and exchange the new code immediately.","Confirm ClientID/ClientSecret and that the authorized redirect URI in Google Cloud Console is exactly https://cloudoauth.files.casaos.app.","Check the logged response body for the error_description field for the precise reason."],"exampleFix":"// before\nreturn fmt.Errorf(e.Error)\n\n// after\nreturn errors.New(e.Error)","handlingStrategy":"validation","validationCode":"if d.ClientID == \"\" || d.ClientSecret == \"\" || d.Code == \"\" {\n\treturn errors.New(\"Google Drive OAuth requires ClientID, ClientSecret and a fresh Code\")\n}","typeGuard":null,"tryCatchPattern":"if err := d.GetRefreshTokenByCode(); err != nil {\n\tif strings.Contains(err.Error(), \"invalid_grant\") || strings.Contains(err.Error(), \"redirect_uri_mismatch\") {\n\t\t// regenerate code / fix console redirect URI; do not retry same code\n\t}\n\treturn err\n}","preventionTips":["Register https://cloudoauth.files.casaos.app as an authorized redirect URI in Google Cloud Console","Automate the code handoff so it is exchanged within seconds of consent","Keep ClientID/ClientSecret in versioned config, validated at startup"],"tags":["google-drive","oauth","authorization-code","authentication"],"backgroundTag":null,"analyzedSha":"0d3b2f444ec0193193cf03eef6d43c6e35b0183e","analyzedAt":"2026-08-15T13:27:57.821Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}