Describe the problem/error/question
I’m running self-hosted on an Ubuntu VPS with n8n in Docker and SQLite database, and today I’m running into an issue with Google Sheets quotas and executions piling up.
Context
n8n 2.21.x in Docker Compose, SQLite database mounted on volume.
“Classic” mode (no external queue), N8N_CONCURRENCY_PRODUCTION_LIMIT now set to
Runners enabled (N8N_RUNNERS_ENABLED=true).
Insights/diagnostics n8n disabled (N8N_INSIGHTS_ENABLED=false, N8N_DIAGNOSTICS_ENABLED=false) to avoid unrelated SQLite errors.
Workflow Architecture
-
Webhook Workflow (creating requests)
HTTP Webhook that receives a structured support request.
Code node “Standardize payload” that maps and cleans fields (category, subcategory, email, message, attachments, request ID, etc.).
Switch “Route by category” that sends to three branches (e.g., LED Strip / Power Supply / Enclosure).
Each branch does a Google Sheets → append to a dedicated sheet tab in the same file (one row per request, with initial Status and Decision “Pending”).
This workflow behaves well. -
Scheduled Workflow (processing pending rows)
This is the one causing problems.
Schedule Trigger set to 1 minute (in the JSON export).
Get row(s) in sheet v4.7:
Resource: Sheet Within Document.
Operation: Get Row(s).
Document: By ID (Google Sheet ID).
Sheet: By ID (tab ID).
Range: I1:I100 or I1:I1000 (Status column with header).
Filter: Status column = pending_validation.
Option enabled: “Return only First Matching Row” to process only one row per execution.
Code “Prepare — LED Strip”:
retrrieves the row (Decision, Status, Color, Email, etc.),
ignores if Decision is empty / “Pending”, or if Status ≠ pending_validation, or Decision not recognized,
calculates promo code + product links,
outputs structured JSON (with a row index) that is then used for Gorgias and to update the sheet.
Based on the decision, the rest of the workflow:
sends a ticket/response via Gorgias,
updates the Status in the sheet (multiple Update row in sheet nodes depending on the case),
updates other tabs if necessary.
Observed Problems
A. Executions in bursts “Starting soon / Queued”
In the Executions tab, I regularly see:
a series of “Starting soon / Queued at HH:MM:SS” executions with the same timestamp,
whereas the interface indicates “No active executions”.
Before disabling insights, the logs showed additional repeated SQLite errors related to internal metrics (“Error while saving insights metadata and raw data”, SQLITE_ERROR: ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint). After adding N8N_INSIGHTS_ENABLED=false and restarting, these errors disappeared.
B. Google Sheets 429 / quota exceeded error
The Get row(s) in sheet node always ends up failing with:
The service is receiving too many requests from you
Quota exceeded for quota metric ‘Read requests’ and limit ‘Read requests per minute per user’ of service ‘sheets.googleapis.com’ (quota at 60 reads/minute).
Looking at the metrics on Google Cloud, I see many more GetSpreadsheet / read_requests than I would expect for a simple “get rows” running every 1–2 minutes, especially with the new “Return only First Matching Row” option.
What I’ve already tried
On n8n side: Concurrency reduced to 1 (N8N_CONCURRENCY_PRODUCTION_LIMIT=1).
Insights/diagnostics disabled to eliminate SQLite noise.
On Sheets v4.7 node: Switched from Document / Sheet “From list” to By ID.
Explicit range I1:I1000 including row 1 (headers), otherwise n8n couldn’t find the Status column.
Filter Status = pending_validation.
“Return only First Matching Row” option enabled to process only one row per run.
On “Prepare — LED Strip” code:
Added safeguard: if input is empty (items.length === 0), return to stop the workflow,
filter out all non-relevant rows before sending anything to Gorgias or Update nodes.
I’m also considering:
reducing the Schedule Trigger frequency (from 1 minute to 5 minutes),
verifying that no other n8n workflow is hitting the same Sheets with the same account.
What kind of feedback I’m looking for
Have others noticed, with version 4.7 of the Google Sheets “Get row(s) in sheet” node (Sheet Within Document, By ID), very high read_requests volume even in “Return only First Matching Row” mode + restricted range?
Do you have a “safe” pattern for processing Google Sheets rows at regular intervals, respecting the ReadRequestsPerMinutePerUser = 60 quota?
For example: read one row per execution, make sure we’re not re-reading the same sheet in all branches, etc.
Would you recommend:
staying on v4.7 but with different config,
going back to an older node version (4.5) for this use case,
completely moving this logic out of Google Sheets (Apps Script, dedicated DB, etc.)?
I’m open to experience sharing / best practices, especially for:
limiting repetitive GetSpreadsheet calls,
avoiding bursts of “Starting soon / Queued” executions,
and keeping something stable without changing the architecture entirely.
What is the error message (if any)?
Please share your workflow
(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
Share the output returned by the last node
Information on your n8n setup
- n8n version:
- Database (default: SQLite):
- n8n EXECUTIONS_PROCESS setting (default: own, main):
- Running n8n via (Docker, npm, n8n cloud, desktop app):
- Operating system: