{"record":{"id":"ccc69df35a583fe2","repo":"decolua/9router","slug":"callbackparams-error-description-callbackpara-ccc69d","errorCode":null,"errorMessage":"${callbackParams.error_description || callbackParams.error}","messagePattern":"\\$\\{callbackParams\\.error_description \\|\\| callbackParams\\.error\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/services/gemini.js","lineNumber":205,"sourceCode":"\n      await new Promise((resolve, reject) => {\n        const timeout = setTimeout(() => {\n          reject(new Error(\"Authentication timeout (5 minutes)\"));\n        }, 300000);\n\n        const checkInterval = setInterval(() => {\n          if (callbackParams) {\n            clearInterval(checkInterval);\n            clearTimeout(timeout);\n            resolve();\n          }\n        }, 100);\n      });\n\n      close();\n\n      if (callbackParams.error) {\n        throw new Error(callbackParams.error_description || callbackParams.error);\n      }\n\n      if (!callbackParams.code) {\n        throw new Error(\"No authorization code received\");\n      }\n\n      spinner.start(\"Exchanging code for tokens...\");\n\n      // Exchange code for tokens\n      const tokens = await this.exchangeCode(callbackParams.code, redirectUri);\n\n      spinner.text = \"Fetching user info...\";\n\n      // Get user info\n      const userInfo = await this.getUserInfo(tokens.access_token);\n\n      spinner.text = \"Fetching project ID...\";\n","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/services/gemini.js#L187-L223","documentation":"During the Gemini OAuth authorization-code flow, the local callback server captures query params from Google's redirect. If Google redirects back with an `error` (and optionally `error_description`) parameter instead of an authorization code, connect() throws an Error with the description (or bare error code) at gemini.js:205. This is the standard OAuth2 error redirect (RFC 6749 §4.1.2.1), e.g. `access_denied`.","triggerScenarios":"The user denies consent on Google's authorization page, Google rejects the request (e.g. redirect_uri/client_id mismatch, invalid scope), or the app is unverified and the user clicks through an 'unsafe' warning canceling the flow — any of which sends `?error=...` to http://localhost:<port>/callback.","commonSituations":"User clicked 'Cancel' on the consent screen; the Google Cloud project's OAuth consent screen is in testing mode and the user's email is not added as a test user; the OAuth client's authorized redirect URI doesn't include the exact localhost callback, so Google returns redirect_uri_mismatch.","solutions":["Retry the connect flow and click Allow on the Google consent screen.","If the error is `redirect_uri_mismatch`, confirm the OAuth client (GEMINI_CONFIG.clientId) registers the exact `http://localhost:<port>/callback` redirect URI.","If `access_denied` or `unverified_app`, add your Google account as a test user on the project's OAuth consent screen.","Read the thrown description (error_description) — it names the exact OAuth error code to address."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const authUrl = new URL(authUrlString);\nconst redirectUri = authUrl.searchParams.get('redirect_uri');\nif (!redirectUri || !redirectUri.startsWith('http://localhost:')) {\n  throw new Error('Invalid redirect_uri configured for Gemini OAuth client');\n}","typeGuard":"function isOAuthErrorParams(params) {\n  return params !== null && typeof params === 'object' && typeof params.error === 'string' && params.error.length > 0;\n}","tryCatchPattern":"try {\n  await geminiService.connect();\n} catch (err) {\n  if (/access_denied|redirect_uri_mismatch|unverified/i.test(err.message)) {\n    console.error(`Google authorization failed (${err.message}). Retry and click Allow; add your account as a test user if the app is unverified.`);\n  }\n  throw err;\n}","preventionTips":["Before starting the flow, add your Google account as a test user on the OAuth consent screen if the app is in testing mode.","Ensure the redirect URI pattern http://localhost:<any-port>/callback is registered on the Google OAuth client.","Never manually edit the callback URL in the browser; let the redirect land naturally.","Retry the flow once after a denial — many denials are accidental misclicks."],"tags":["oauth","google","authentication","user-input"],"backgroundTag":"oauth-access-denied","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}