My App Works for Me but Not for Other Users

Written By
SprintX Team
AI & Product Engineering
August 04, 2026
8 min read

A diagnostic guide for the app that works perfectly on your account and breaks for every other user, including the security problems hiding behind the symptom.
You demo the app and it is flawless. You send the link to five beta users and get five different flavors of failure: an empty dashboard, a spinner that never resolves, a permission error, a page that loads but shows nothing.
You log in again. Everything works. You start to suspect the users.
Do not. This symptom has a small number of causes, and the reason it hides from you is structural: your account is the account the app was built around. It has data, it has elevated permissions, it has a warm cache, and it lives in your browser. Every other user has none of that. Here is how to find which one is biting you, and why one of the possible answers is a security incident rather than a bug.
First, reproduce it properly
Ninety percent of the diagnosis is in reproducing the failure yourself, and most founders skip it because they test in the browser they built in.
Do this before anything else:
- Open a private window and sign up as a genuinely new user. Not your existing account in incognito — a new email, through the real signup flow.
- Keep the console and network tab open from before you load the page. The first failed request is the answer; the seventeenth is noise.
- Note the status code. A 401 means auth, 403 means permissions, 404 means a routing or ID assumption, 500 means server error, and a 200 that returns an empty array means the query ran and found nothing — a completely different problem with a completely different fix.
- Check whether it fails on first load or after an action. First load points at data and permissions. After an action points at write rules or validation.
That empty-array-with-a-200 case is the one people misdiagnose most. Nothing is broken, technically. The user simply cannot see the rows, and now you need to know why.
The seven causes, in order of likelihood
1. Row-level security you enabled but never tested per role
The most common cause in Supabase and Postgres-backed apps. RLS is on, and the policy either references the wrong column, checks against a table your new user has no row in, or was written for the shape of your own account.
The tell: your data loads, theirs returns an empty set with no error. Policies fail closed and silently, which is correct behavior and terrible for debugging.
Test policies as a real user, not as service role. Anything you run from the SQL editor or with the service key bypasses RLS entirely, which is exactly why this bug survives to production. The specific patterns that break are catalogued in RLS mistakes in AI-built apps, and if you are staring at a policy right now, why RLS is not working is the faster read.
2. Your account has data nobody else does
You built the app with your own records. Every screen was developed against a populated account. New users hit the same screens with zero rows, and code written for the happy path throws where a first element, a length, or a nested field is assumed to exist.
The tell: blank screens, spinners forever, or an error mentioning undefined properties. Symptoms appear on the first screen after signup and disappear as soon as the user creates one record.
The fix is real empty states on every list, chart, and detail view — plus onboarding that seeds the first record if a screen genuinely cannot render without one.
3. Your account is secretly an admin
Somewhere in the code is a flag, a hardcoded email, or a role that was set by hand on your row. You have permissions no signup flow grants. Everything you test passes because you are testing as the one account that can do anything.
The tell: 403s from actions that work perfectly for you. Check your own user row and compare it, field by field, against a fresh signup's row. Differences you did not intend are your bug.
4. Cached state and old sessions
Your browser holds a valid token, a populated local storage, and cached bundles. A new user gets a cold start. Failures that only affect first-time visitors — a missing token refresh, a race between auth and the first data fetch, a stale service worker — are invisible to you permanently.
The tell: it works in your normal browser, fails in a private window, and works again after a hard refresh. That pattern is diagnostic on its own.
5. Data written without an owner
Records created by your account carry your user ID. Records created through the real flow may not, if the insert never sets the owner column or the tenant ID. Then filters return nothing, or worse, return everything.
The tell: new users see either an empty list or other people's data. The second version is not a bug report, it is a breach — stop and treat it as one.
6. Environment and browser assumptions
Your machine has a specific browser, a specific timezone, a specific screen size, and a fast connection. Your users do not. Safari on iOS handles storage and cookies differently from Chrome on a desktop; a date function that assumes UTC shows the wrong day for half the planet; a layout tested at 1440px is unusable at 390px. If failures cluster by device, start with mobile-specific breakage.
7. Rate limits and quotas that only bite under concurrency
You are one user. Ten users at once exhaust a database connection pool, hit a per-key limit on an upstream API, or trigger a serverless cold-start pile-up. The tell is that failures correlate with load rather than with account, and everything looks fine the moment you check. Crashes under multiple users covers this class specifically.
Match the symptom to the cause
| What the other user sees | Most likely cause | Confirm by |
|---|---|---|
| Empty dashboard, no error | RLS policy or missing owner column | Run the same query as their user ID, not service role |
| Spinner that never finishes | Unhandled empty state or a rejected promise | Console for an uncaught error; network for a pending request |
| 403 on a button that works for you | Your account has elevated role | Diff your user row against a fresh signup |
| Works after a refresh | Auth race or stale cache | Private window, throttled network |
| Someone else's data appears | Broken tenant isolation | Treat as an incident, not a bug |
| Fails only on phones | Browser or viewport assumption | Real device, not just responsive mode |
The version of this that is not a bug
Two of the seven causes above are security problems wearing a usability costume.
If a new user can see records belonging to another user, tenant isolation is broken and you have a data exposure. If your app "works" for everyone because access checks live in frontend filters rather than in the database or API, then it is not working for anyone — it is failing safely by accident. Escape.tech found over 2,000 vulnerabilities across 5,600 vibe-coded apps, and broken access control is the most common category by a wide margin, precisely because it does not announce itself.
The rule of thumb: any bug where the fix is "filter the results better in the UI" is a bug where the real fix belongs in the database. If your app has real customers and you are not certain which layer enforces access, an audit of the codebase will tell you in days, and multi-tenancy done properly covers what the correct shape looks like.
Frequently asked questions
Why does everything work in the Supabase SQL editor but not in my app? Because the editor uses the service role, which bypasses row-level security completely. Your app uses the anon key plus the user's JWT, which does not. Any test that passes in the editor tells you nothing about what a real user can access.
Should I just turn RLS off until launch? No. Turning it off makes every row readable by anyone with your public anon key, which is embedded in your frontend and therefore public. That converts a bug affecting five beta users into an open database. Fix the policies instead, and test them as a real user.
How do I test as another user without asking someone? Create two or three throwaway accounts with different roles and keep them in separate browser profiles, not tabs. Better still, add a scripted end-to-end test that signs up fresh and walks the core flow — it catches this whole class of bug on every deploy instead of at every launch.
If your app only behaves for the account you built it with, the gap is usually access rules and empty states, and both are fixable in days. SprintX tests your app as every role it actually has, fixes the isolation properly at the database layer, and leaves you tests that catch it next time. Send us a login and your repo.


