Error Handling
SheetsAPI error codes, response shapes, and retry strategies for building resilient integrations.
SheetsAPI uses standard HTTP status codes. All error responses include a JSON body with a
message field so you can surface meaningful errors to users or log them for debugging.
Error response shape
{
"error": "Unauthorized",
"message": "Missing or invalid API key.",
"status": 401
}All 4xx and 5xx responses follow this shape. The error field is a short machine-readable
string; message is a human-readable description.
Status codes
| Code | Meaning | Common cause |
|---|---|---|
400 | Bad Request | Malformed query params (e.g. non-numeric limit) |
401 | Unauthorized | Missing Authorization header or invalid key |
403 | Forbidden | Key is valid but not authorised for this sheet |
404 | Not Found | User key or sheet name does not exist |
429 | Too Many Requests | Rate limit exceeded - see Rate limits |
500 | Internal Server Error | Unexpected error on the SheetsAPI side |
502 | Bad Gateway | Google Sheets API is unreachable or returned an error |
504 | Gateway Timeout | Google Sheets took too long to respond |
Handling errors in JavaScript
const response = await fetch(
`https://sheetsapi.gkit.mreshank.com/api/spreadsheets/YOUR_USER_KEY/Products`,
);
if (!response.ok) {
const err = await response.json();
// err.status, err.error, err.message are all available
throw new Error(`SheetsAPI ${err.status}: ${err.message}`);
}
const { data, meta } = await response.json();Using the TypeScript client helper
If you are using the TypeScript client, errors are
thrown automatically when the response is not ok:
try {
const result = await client.list<Product>("Products", { limit: 20 });
console.log(result.data);
} catch (err) {
if (err instanceof Error) {
console.error("SheetsAPI error:", err.message);
}
}401 Unauthorized
This means the Authorization header is missing or the key is invalid.
GET /api/spreadsheets/YOUR_USER_KEY/Products
→ 401 Unauthorized
Check that:
- Your request includes the
Authorization: Bearer sk_...header. - The key has not been revoked in the dashboard.
- You are using the correct key - keys are shown in full only once at creation.
For public sheets (no API key required), omit the Authorization header entirely. A 401
on a public sheet means the sheet's key is wrong, not that auth is required.
404 Not Found
This can mean one of two things:
- User key is wrong - double-check
YOUR_USER_KEYin the URL. - Sheet name is wrong - the sheet name is the tab name inside the spreadsheet, not the spreadsheet title. It is case-sensitive.
GET /api/spreadsheets/bad_key/Products
→ 404 Not Found: "User not found"
GET /api/spreadsheets/YOUR_USER_KEY/products ← lowercase "p"
→ 404 Not Found: "Sheet not found"
429 Too Many Requests
You have exceeded the rate limit. The response includes a Retry-After header with the
number of seconds to wait before retrying.
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Retry after 12 seconds.",
"status": 429
}
Implement exponential backoff for automated clients:
async function fetchWithRetry(url: string, options?: RequestInit, attempt = 0): Promise<Response> {
const response = await fetch(url, options);
if (response.status === 429 && attempt < 4) {
const retryAfter = Number(response.headers.get("Retry-After") ?? 2);
const delay = Math.max(retryAfter * 1000, Math.pow(2, attempt) * 1000);
await new Promise((r) => setTimeout(r, delay));
return fetchWithRetry(url, options, attempt + 1);
}
return response;
}See Rate limits for the full quota table.
502 / 504 Gateway errors
These mean Google Sheets itself was unavailable or slow. They are transient - retry with backoff. If they persist, check the GKit status page and Google Workspace Status Dashboard.
const RETRYABLE = new Set([429, 502, 503, 504]);
if (RETRYABLE.has(response.status)) {
// safe to retry
}Best practices
- Always check
response.okbefore parsing the body - a non-ok JSON body is an error object, not a data object. - Log
err.messagefrom the error body rather than just the status code - the message tells you exactly what went wrong. - Retry only transient errors (
429,502,503,504) - do not retry4xxerrors that indicate a bug in your request (wrong URL, wrong key, wrong params). - Surface 401 / 403 to users - these usually need a human action (add an API key, fix permissions) rather than a code retry.