ToolJet/ToolJet · error · OAuthUnauthorizedClientError
Query could not be completed
Error message
Query could not be completed
What it means
In the Google Sheets run() catch block, when authentication_type is NOT 'service_account' and the HTTP response status is 401 or 403, the plugin throws OAuthUnauthorizedClientError (a distinct Error subclass signaling the OAuth token is invalid/expired so ToolJet can prompt re-auth) instead of the generic QueryError. This branch exists specifically to tell the platform the user must re-authorize.
Source
Thrown at plugins/packages/googlesheets/lib/index.ts:182
const errorRespose = JSON.parse(error.response.body);
errorDetails = {
message: errorRespose?.error?.message,
status: errorRespose?.error?.status,
};
}
if (error.message.replace(/\s+/g, ' ').trim().includes('Unexpected token in JSON')) {
errorDetails = {
message: 'Invalid JSON',
};
}
// For OAuth if token is expired or invalid it returns 401 or 403
// For other authentication types just throw generic error so that user can re-authenticate
if (
sourceOptions['authentication_type'] !== 'service_account' &&
(error?.response?.statusCode === 401 || error?.response?.statusCode === 403)
) {
throw new OAuthUnauthorizedClientError('Query could not be completed', error.message, {
...error,
...errorDetails,
});
}
throw new QueryError('Query could not be completed', error.message, errorDetails);
}
return {
status: 'ok',
data: result,
};
}
async refreshToken(sourceOptions) {
if (!sourceOptions['refresh_token']) {
throw new QueryError('Query could not be completed', 'Refresh token empty', {});
}
const accessTokenUrl = 'https://oauth2.googleapis.com/token';View on GitHub (pinned to 20602a8e10)
Solutions
- Re-authorize the Google Sheets datasource through the ToolJet OAuth flow to obtain a fresh access+refresh token.
- Ensure GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET env vars on the ToolJet server match the Google Cloud OAuth app used for the original consent.
- Confirm the OAuth consent screen includes the spreadsheets scope; re-consent if scopes changed.
- If the issue is only an expired access token, verify refreshToken() (lines 196+) can exchange the refresh_token successfully.
Example fix
// no code fix — user must re-run the OAuth consent flow in the datasource settings
Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-call validation can prevent an expired access token; detect at runtime. // Proactively refresh before the 1h window: schedule refreshToken() calls.
Type guard
function isOAuthUnauthorized(e: unknown): e is OAuthUnauthorizedClientError { return e instanceof Error && e.name === 'OAuthUnauthorizedClientError'; } Try / catch
try { await plugin.run(sourceOptions, queryOptions); }
catch (e) {
if (e instanceof OAuthUnauthorizedClientError) { /* trigger re-consent / refresh flow, then retry once */ }
else throw e;
} Prevention
- Ensure access_type=offline and prompt=consent on the original OAuth grant.
- Keep GOOGLE_CLIENT_ID/SECRET stable so refresh succeeds.
- Refresh the access token before the 1h expiry instead of waiting for a 401.
When it happens
Trigger: OAuth access token expired (Google access tokens last ~1h) and a read/append/update/delete/info/list_all call returned 401. The user revoked ToolJet access in their Google account, producing 401/403. The refresh token is invalid or was never persisted. The OAuth app scopes were changed and the existing grant no longer covers spreadsheets.
Common situations: Long-running app sessions past the 1h access-token window where the refresh path failed. User manually revoked the consent. GOOGLE_CLIENT_ID/SECRET env vars changed so refresh fails. App restored from an export where the OAuth grant did not carry over. Migrating between ToolJet instances without re-consent.
Related errors
- could not connect to Googlesheets
- access_token not found in the response
- Connection could not be established
- could not connect to Googlesheets
- Missing access token
AI-assisted analysis of ToolJet/ToolJet@20602a8e10 (2026-08-13).
Data as JSON: /api/errors/ff92e6c2de4d2e5c.
Report an issue: GitHub.