FlowiseAI/Flowise · error · Error

Google Sheets API Error ${response.status}: ${response.statu

Error message

Google Sheets API Error ${response.status}: ${response.statusText} - ${errorText}

What it means

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.

Source

Thrown at packages/components/nodes/tools/GoogleSheets/core.ts:155

    }): Promise<string> {
        const url = `https://sheets.googleapis.com/v4/${endpoint}`

        const headers = {
            Authorization: `Bearer ${this.accessToken}`,
            'Content-Type': 'application/json',
            Accept: 'application/json',
            ...this.headers
        }

        const response = await fetch(url, {
            method,
            headers,
            body: body ? JSON.stringify(body) : undefined
        })

        if (!response.ok) {
            const errorText = await response.text()
            throw new Error(`Google Sheets API Error ${response.status}: ${response.statusText} - ${errorText}`)
        }

        const data = await response.text()
        return data + TOOL_ARGS_PREFIX + JSON.stringify(params)
    }
}

// Spreadsheet Tools
class CreateSpreadsheetTool extends BaseGoogleSheetsTool {
    defaultParams: any

    constructor(args: any) {
        const toolInput = {
            name: 'create_spreadsheet',
            description: 'Create a new Google Spreadsheet',
            schema: CreateSpreadsheetSchema,
            baseUrl: '',
            method: 'POST',

View on GitHub (pinned to abe4a8601a)

Solutions

  1. 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.
  2. 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.
  3. For 404, verify spreadsheetId — extract only the long ID segment from the URL between /d/ and /edit, not the whole URL.
  4. For 429, reduce concurrency, add exponential backoff between batch_get/batch_update calls, or request a quota increase in GCP.
  5. 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').

Example fix

// before — token expired, gets 401
const tools = createGoogleSheetsTools({ accessToken: staleToken, actions })
// after — pass the Flowise credential so makeGoogleSheetsRequest receives a freshly refreshed token
const tools = createGoogleSheetsTools({ accessToken: await refreshAccessToken(credential), actions })
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling any Google Sheets tool, sanity-check the token and id shape
function assertSheetsReady(spreadsheetId: string, accessToken: string) {
  if (!accessToken) throw new Error('accessToken missing — refresh the OAuth credential')
  if (!/^[a-zA-Z0-9-_]{30,}$/.test(spreadsheetId)) throw new Error(`spreadsheetId looks malformed: ${spreadsheetId}`)
  // optional cheap probe
  return fetch(`https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}?fields=spreadsheetId`, {
    headers: { Authorization: `Bearer ${accessToken}` }
  }).then(r => { if (!r.ok) throw new Error(`probe failed: ${r.status}`) })
}

Type guard

function isSheetsError(e: unknown): e is Error {
  return e instanceof Error && /^Google Sheets API Error \d{3}:/.test(e.message)
}

Try / catch

try {
  return await tool.invoke(args)
} catch (e) {
  if (isSheetsError(e)) {
    const code = Number(e.message.match(/\b(\d{3})\b/)?.[1])
    if (code === 401) await refreshAccessToken()
    if (code === 429) await backoff()
    if (code === 404) throw new Error(`spreadsheet not found — check id`, { cause: e })
  }
  throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/c32cc7b026637773. Report an issue: GitHub.