FlowiseAI/Flowise · error · Error
Failed to get spreadsheet metadata: ${response.status} ${res
Error message
Failed to get spreadsheet metadata: ${response.status} ${response.statusText} - ${errorText} What it means
Thrown by GoogleSheets.getSpreadsheetMetadata after a non-ok response from GET https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}. The message includes the HTTP status code, status text, and the raw response body, so it is the authoritative source for why the Google Sheets API rejected the metadata call.
Source
Thrown at packages/components/nodes/documentloaders/GoogleSheets/GoogleSheets.ts:325
finaltext += `${doc.pageContent}\n`
}
return handleEscapeCharacters(finaltext, false)
}
}
private async getSpreadsheetMetadata(spreadsheetId: string, accessToken: string): Promise<any> {
const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}`
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Failed to get spreadsheet metadata: ${response.status} ${response.statusText} - ${errorText}`)
}
return response.json()
}
private async getSheetData(spreadsheetId: string, range: string, valueRenderOption: string, accessToken: string): Promise<any> {
const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${encodeURIComponent(range)}`
const params = new URLSearchParams({
valueRenderOption,
dateTimeRenderOption: 'FORMATTED_STRING',
majorDimension: 'ROWS'
})
const response = await fetch(`${url}?${params}`, {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}View on GitHub (pinned to abe4a8601a)
Solutions
- Decode the status code in the message: 401 → re-authorize/refresh the OAuth token; 403 → add the service account email as a viewer on the sheet and confirm spreadsheets.readonly scope; 404 → correct the spreadsheetId; 429 → add exponential backoff or reduce request volume.
- Confirm the credential uses the same Google Cloud project that enabled the Google Sheets API.
- Ensure the access token is fetched at call time, not cached across long-lived sessions.
- Add retry-with-backoff around getSpreadsheetMetadata specifically for 429/503 responses.
Example fix
// before
const response = await fetch(url, { headers })
if (!response.ok) {
const errorText = await response.text()
throw new Error(`Failed to get spreadsheet metadata: ${response.status} ${response.statusText} - ${errorText}`)
}
// after - retry transient failures
async function fetchWithRetry(url, opts, attempts = 3) {
for (let i = 0; i < attempts; i++) {
const r = await fetch(url, opts)
if (r.ok || (r.status !== 429 && r.status < 500)) return r
await new Promise(res => setTimeout(res, 2 ** i * 500))
}
const r = await fetch(url, opts)
return r
} Defensive patterns
Strategy: retry
Validate before calling
// Validate the token will likely work: call a cheap userinfo endpoint first
async function tokenLooksValid(accessToken) {
const r = await fetch('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' + accessToken)
return r.ok
} Type guard
function isHttpError(e, statusStart = 400) {
return typeof e?.message === 'string' && /Failed to get spreadsheet metadata:\s*(\d{3})/.test(e.message)
&& Number(RegExp.$1) >= statusStart
} Try / catch
async function getMetadataWithRetry(id, token, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try { return await loader.getSpreadsheetMetadata(id, token) }
catch (e) {
const m = e.message.match(/(\d{3})/)
const code = m ? Number(m[1]) : 0
if ((code === 429 || code >= 500) && i < attempts - 1) {
await new Promise(r => setTimeout(r, 2 ** i * 500)); continue
}
throw e
}
}
} Prevention
- Request spreadsheets.readonly scope on the OAuth credential.
- Share the spreadsheet with the service account email.
- Refresh access tokens at call time rather than caching long-term.
- Add backoff for 429/5xx responses.
When it happens
Trigger: 401 when the access token is expired/revoked; 403 when the token lacks spreadsheets.readonly scope or the spreadsheet is not shared with the service account email; 404 when spreadsheetId is wrong or the sheet was deleted; 429 when the per-user/per-project quota is exhausted.
Common situations: Token auto-refresh not wired up so a cached token goes stale; service account email not added as a viewer on the target sheet; user copies only part of the spreadsheetId (e.g. includes the #gid fragment); hitting the Sheets API read quota during a large crawl.
Related errors
- Failed to get sheet data: ${response.status} ${response.stat
- Failed to load Google Sheets data: ${error.message}
- Oxylabs: Failed to call Oxylabs API: ${response.status}
- Google Sheets API Error ${response.status}: ${response.statu
- ${errorMessage}
AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12).
Data as JSON: /api/errors/fa11657d2d9f8336.
Report an issue: GitHub.