Budibase/budibase · error · Error
Error authenticating with google sheets. ${json.error_descri
Error message
Error authenticating with google sheets. ${json.error_description} What it means
fetchAccessToken exchanges the OAuth code/refresh token with Google's token endpoint. Any non-200 response (invalid code, expired refresh token, bad client secret, revoked grant) results in this error, with Google's error_description interpolated into the message. It signals the datasource cannot obtain a valid access token.
Source
Thrown at packages/server/src/integrations/googlesheets.ts:224
private async fetchAccessToken(
payload: AuthTokenRequest
): Promise<AuthTokenResponse> {
const response = await fetch("https://www.googleapis.com/oauth2/v4/token", {
method: "POST",
body: JSON.stringify({
...payload,
grant_type: "refresh_token",
}),
headers: {
"Content-Type": "application/json",
},
})
const json = await response.json()
if (response.status !== 200) {
throw new Error(
`Error authenticating with google sheets. ${json.error_description}`
)
}
return json
}
private async connect() {
try {
const bbCtx = context.getCurrentContext()
let oauthClient = bbCtx?.googleSheets?.oauthClient
if (!oauthClient) {
await setupCreationAuth(this.config)
// Initialise oAuth client
const googleConfig = await configs.getGoogleDatasourceConfig()
if (!googleConfig) {View on GitHub (pinned to a81a902e9a)
Solutions
- Read the error_description in the message and match it to Google's OAuth error docs (invalid_grant, invalid_client, etc.)
- Re-run the Google Sheets OAuth authorization flow in the Budibase builder to get a fresh code/refresh token
- Verify the Google datasource config clientID/clientSecret in the workspace match the Google Cloud OAuth client
- If invalid_grant on refresh, the refresh token was revoked or expired — reconnect the datasource
- Check server can reach https://oauth2.googleapis.com (proxy/firewall)
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check config before attempting token exchange
function canAttemptAuth(config) {
return Boolean(config && config.clientId && config.clientSecret && (config.code || config.refreshToken))
} Try / catch
try {
const json = await fetchAccessToken(...)
} catch (err) {
if (err.message.startsWith('Error authenticating with google sheets.')) {
if (err.message.includes('invalid_grant')) {
// restart the OAuth consent flow for a fresh code/refresh token
} else if (err.message.includes('invalid_client')) {
// fix clientID/clientSecret in the Google datasource config
}
} else throw err
} Prevention
- Never reuse an authorization code; run a fresh OAuth flow each time
- Refresh tokens proactively before expiry instead of on-demand
- Verify clientID/clientSecret against Google Cloud Console after rotations
- Notify users to re-link the datasource if they revoke access in their Google account
When it happens
Trigger: Calling fetchAccessToken (via tokenResponse) when Google returns status != 200 — e.g. authorization code already redeemed/expired, refresh token revoked by the user, or mismatched clientID/clientSecret in the OAuth token request.
Common situations: Re-using an auth code from a completed OAuth flow; user revoked app access in their Google account; Google OAuth client credentials changed/rotated server-side; clock/network issues causing Google to reject the request; sandbox app in testing mode with expired grants.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Teams OAuth token request failed (${resp.status}): ${await r
- ${err.message}
- Failed to exchange Microsoft OAuth code
- Google config not found
- Unable to retrieve datasource authentication cookie
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/b5fc2c04c8e4e6ac.
Report an issue: GitHub.