What Breaks When Apps Script Projects Sprawl
What breaks when Apps Script projects multiply and ownership, triggers, permissions, and versions become scattered.
Pitfalls, code, and guidelines for developers building on GAS — the groundwork AXDX is built on.
What breaks when Apps Script projects multiply and ownership, triggers, permissions, and versions become scattered.
The common reasons a daily Apps Script trigger suddenly stops, and what operators should check first.
What can go wrong when customer data is stored in the browser, from security exposure to retention and deletion risk.
Mobile localStorage drops data silently when it fills up — but the 'saved' flag stays, so a Done check shows with no data. Which store to use for what, keeping large bodies in IndexedDB, an integrity check on open, and cutting eviction with storage.persist().
In GAS, scopes, triggers, and permissions fail silently. Miss one manifest scope and the trigger never runs. Why it fails silently, installing idempotently to dodge the 20-trigger cap, a heartbeat, and proving it ran right after install.
Apps Script goes to 100% of users the instant you promote — there's no canary. The difference between push and deploy, shipping new checks on a compat → warn → enforce ladder, telemetry that counts old clients, and the rollback command when it goes wrong.
Google Sheets silently coerces strings like '2026-06' into a Date. When save, read, and compare each compute the month differently, completion is rejected forever. What gets coerced, how to pin cells to text and guard on read, plus batch writes and formula injection.
The places I actually got stuck building the CheckReport Demo, with the code. Concurrent saves to a shared sheet are blocked with ScriptLock + an idempotency key, cells hold only metadata, and exports are cut off with a time budget. Good code and bad code, side by side.
In GAS the slow part isn't JavaScript, it's service calls to Sheets and Drive. Swap in-loop getValue/setValue for batched getValues/setValues and it's tens of times faster.
A Google Sheets cell caps at 50,000 characters. Put a photo or signature in a record row as a data URL and the save breaks. Keep only metadata in the cell.
The 'execute as' × 'who can access' combination sets data permissions and whether your code is exposed. Public apps need their own app-level auth.
Apps Script kills any single run at 6 minutes. Design bulk jobs as chunk + cursor + time-trigger resume, or you get the half-processed-data accident.
A Properties value caps near 9KB. Cache only data you can lose. Big state goes to Sheet, Drive, or an external DB. Plain JSON loses types.
Capturing the DOM via SVG foreignObject freezes or returns a blank image on mobile Safari and the GAS iframe. Draw to canvas directly, and download via Web Share.
When users and triggers write the same asset, numbers collide and rows get overwritten. Guard with tryLock + finally + flush, and design for the 30-per-user concurrency ceiling.
Reuse the deployment ID when you push a new version with clasp and the /exec URL stays fixed. Guard shared sheet writes with LockService.
Transient failures like 429, 503, and timeouts can be recovered by retrying. But never retry a non-idempotent write without an idempotency key, and stop before 6 minutes.
Loading data in the template delays first paint. Draw the shell first and load via google.script.run, but attach a failure handler to every call.
GAS is strong at short automation and weak at long-running, high-volume, high-concurrency work. Quotas are shared per account. Know the signals and plan the move.
Add classification, summary, and drafts by calling Vertex AI (Gemini) straight from GAS. Hand heavy work that exceeds 6 minutes to Cloud Run. A human-approval gate stays mandatory.