{"record":{"id":"c32cc7b026637773","repo":"FlowiseAI/Flowise","slug":"google-sheets-api-error-response-status-resp","errorCode":null,"errorMessage":"Google Sheets API Error ${response.status}: ${response.statusText} - ${errorText}","messagePattern":"Google Sheets API Error (.+?): (.+?) - (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/nodes/tools/GoogleSheets/core.ts","lineNumber":155,"sourceCode":"    }): Promise<string> {\n        const url = `https://sheets.googleapis.com/v4/${endpoint}`\n\n        const headers = {\n            Authorization: `Bearer ${this.accessToken}`,\n            'Content-Type': 'application/json',\n            Accept: 'application/json',\n            ...this.headers\n        }\n\n        const response = await fetch(url, {\n            method,\n            headers,\n            body: body ? JSON.stringify(body) : undefined\n        })\n\n        if (!response.ok) {\n            const errorText = await response.text()\n            throw new Error(`Google Sheets API Error ${response.status}: ${response.statusText} - ${errorText}`)\n        }\n\n        const data = await response.text()\n        return data + TOOL_ARGS_PREFIX + JSON.stringify(params)\n    }\n}\n\n// Spreadsheet Tools\nclass CreateSpreadsheetTool extends BaseGoogleSheetsTool {\n    defaultParams: any\n\n    constructor(args: any) {\n        const toolInput = {\n            name: 'create_spreadsheet',\n            description: 'Create a new Google Spreadsheet',\n            schema: CreateSpreadsheetSchema,\n            baseUrl: '',\n            method: 'POST',","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/nodes/tools/GoogleSheets/core.ts#L137-L173","documentation":"Thrown by BaseGoogleSheetsTool.makeGoogleSheetsRequest when the Google Sheets REST API (https://sheets.googleapis.com/v4/...) returns a non-2xx status. The message fuses the HTTP status code, status text, and the raw response body, so the underlying Google error JSON (e.g. {\"error\":{\"code\":403,\"message\":\"...\",\"status\":\"PERMISSION_DENIED\"}}) is inlined verbatim. It is the single error path for every transport-level failure (auth, quota, not-found, validation) across all Spreadsheet/Values/Batch tools.","triggerScenarios":"Any makeGoogleSheetsRequest call whose fetch resolves with response.ok === false. Concretely: 401 when the OAuth2 accessToken is expired/revoked, 403 when the service account lacks the spreadsheets scope or the user has no edit rights, 404 from a wrong/typo spreadsheetId or a deleted sheet, 400 from a malformed range (e.g. an un-encoded range with special chars reaching the encoded path), and 429/503 under API quota exhaustion. Each tool wraps the call in try/catch and converts it via formatToolError, so the agent sees a formatted error string rather than an exception bubble.","commonSituations":"Access token from a Google OAuth credential that expired (tokens live ~1h); a Spreadsheet shared with the wrong account so the service account can't open it; copy-pasting a spreadsheet URL instead of the bare ID; hitting the default 300 read/60 write requests-per-minute-per-user quota during batch jobs; a self-hosted/proxy environment that strips the Authorization header.","solutions":["Read the embedded Google error JSON first — the status field (PERMISSION_DENIED, NOT_FOUND, INVALID_ARGUMENT, RESOURCE_EXHAUSTED) names the exact cause; fix that, not the HTTP code.","For 401/403, re-authorize the Google Sheets OAuth2 credential in the Flowise credential manager so a fresh accessToken is minted; confirm the credential's scopes include drive.file or spreadsheets.","For 404, verify spreadsheetId — extract only the long ID segment from the URL between /d/ and /edit, not the whole URL.","For 429, reduce concurrency, add exponential backoff between batch_get/batch_update calls, or request a quota increase in GCP.","For 400 INVALID_ARGUMENT on ranges, ensure encodeURIComponent runs on params.range (it already does in update/append/clear; pass ranges like 'Sheet1!A1:B2')."],"exampleFix":"// before — token expired, gets 401\nconst tools = createGoogleSheetsTools({ accessToken: staleToken, actions })\n// after — pass the Flowise credential so makeGoogleSheetsRequest receives a freshly refreshed token\nconst tools = createGoogleSheetsTools({ accessToken: await refreshAccessToken(credential), actions })","handlingStrategy":"try-catch","validationCode":"// Before calling any Google Sheets tool, sanity-check the token and id shape\nfunction assertSheetsReady(spreadsheetId: string, accessToken: string) {\n  if (!accessToken) throw new Error('accessToken missing — refresh the OAuth credential')\n  if (!/^[a-zA-Z0-9-_]{30,}$/.test(spreadsheetId)) throw new Error(`spreadsheetId looks malformed: ${spreadsheetId}`)\n  // optional cheap probe\n  return fetch(`https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}?fields=spreadsheetId`, {\n    headers: { Authorization: `Bearer ${accessToken}` }\n  }).then(r => { if (!r.ok) throw new Error(`probe failed: ${r.status}`) })\n}","typeGuard":"function isSheetsError(e: unknown): e is Error {\n  return e instanceof Error && /^Google Sheets API Error \\d{3}:/.test(e.message)\n}","tryCatchPattern":"try {\n  return await tool.invoke(args)\n} catch (e) {\n  if (isSheetsError(e)) {\n    const code = Number(e.message.match(/\\b(\\d{3})\\b/)?.[1])\n    if (code === 401) await refreshAccessToken()\n    if (code === 429) await backoff()\n    if (code === 404) throw new Error(`spreadsheet not found — check id`, { cause: e })\n  }\n  throw e\n}","preventionTips":["Refresh OAuth tokens before expiry; store expiry time alongside the token.","Extract spreadsheetId with a regex from the URL to avoid paste errors.","Add exponential backoff for 429/503 around batch_get/batch_update.","Log the embedded Google error JSON, not just the HTTP code, for faster triage."],"tags":["google-sheets","http","api-error","auth","rate-limit"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}