July 20, 20269 min read

The Bugs That Only Exist on a Phone

Free spatial notes

Put this workflow on an infinite canvas instead of another linear doc.

Start in the browser with no account. Create an account only when you want to sync what you made.

Every One of These Passed Desktop Testing

OmniCanvas runs as a web app and as an installed PWA on phones and tablets. Over several weeks we worked through a cluster of bugs that had one thing in common: none of them were reproducible on a development machine, and none of them were caught by our test suite.

Here they are, with what each one turned out to be about.

1. "Sync Failed: Too Many Folders in One Sync"

The report: sync failing on a phone with a server error about too many folders in a single push.

What was happening: the server enforces a per-request limit on how many folders a sync push may contain. Sensible. The client pushed every pending folder in one request. Also sensible, right up until a user has more folders than the limit.

Note the shape of this bug. It is not a mobile bug at all — the same code would fail identically on desktop. It surfaced on a phone because the phone belonged to the person with the most real data. Limits that scale with usage are discovered by your heaviest users, and your heaviest user is usually you.

The fix: the client now batches pushes at 50 items, for both notes and folders. The test asserts that 120 folders go out as 50, 50, and 20.

The broader lesson is about where a limit gets enforced. A server-side limit with no client-side batching is not a limit, it is a trap that arms itself as a user succeeds with your product. Any paginated or bounded endpoint needs the client to respect the bound, and needs a test at a quantity larger than anyone on the team has locally.

2. iOS: Stranded on "You Can Close This Tab"

The report: after signing in with Google on the iOS PWA, the user was stuck on a blank screen reading "you can close this tab." Killing the app was the only way out.

What was happening: OAuth in an installed PWA on iOS opens an external browser context for the provider. After authentication, that context is supposed to hand control back and close itself. On iOS it does not reliably close, and inside an installed PWA there is no visible browser chrome — no tab bar, no close button, no back gesture that helps. The instruction "you can close this tab" refers to something the user cannot see and has no way to act on.

The fix: two layers. The temporary context now closes itself automatically after the handoff. And because that will not work in every iOS version and configuration, there is a visible fallback button that returns the user to the app.

The rule: never leave a user on a screen whose only instruction requires interface that is not present. Text like "close this window" or "press back" assumes browser chrome. Installed PWAs do not have it. Every terminal state needs an in-page control.

This bug also has a nasty property: it hits during signup, which means the people affected are new users, and new users who cannot complete signup do not file bug reports. We only heard about it because the report came from someone we knew.

3. The Microphone Permission With No Setting

The report: recording works in the mobile PWA, but on a MacBook it reports missing permissions — and the option to grant them does not appear in macOS system settings.

This one was genuinely confusing, because the user's mental model was correct and the platform was not cooperating with it. They looked in the obvious place, the entry was absent, and there was nothing else to try.

The behavior differs by platform, by browser, by installation mode, and by whether a permission was previously denied. A permission denied in a browser context can persist in a way that produces exactly this symptom: the app reports no access, and the operating system has no record of the app to show you.

The fix: when a permission check fails, do not just report that permission is missing. Explain where the permission actually lives for this platform and installation mode, and give the user a direct route there.

Concretely, the failure message now detects the browser by name and says to look for that browser in macOS Microphone settings — not OmniCanvas, and not the installed PWA. That is the detail that made the original bug so baffling: the user searched for the app they were using, and the entry that matters is filed under the browser hosting it. If no entry exists yet, the message explains that microphone access has to be allowed at the site level first, because the operating system does not list an app that has never requested the permission.

There is also a direct link into the macOS Privacy settings pane, and the message varies by what actually failed — no input device found, screen-share audio blocked, or microphone blocked are three different problems with three different next steps.

"Microphone access denied" is a true statement and a useless one. The user already knows something is wrong. What they need is the specific next action on the specific machine they are holding.

4. The Toolbar You Could Not Drag

The report, part one: on mobile, dragging the canvas toolbar just pushed it to the bottom until it got stuck and became unusable.

The report, part two: on desktop, dragging did not track the pointer — the toolbar jumped to a position centered on the cursor and about a hundred pixels above the toolbar itself.

Two symptoms, one root cause: drag was implemented against mouse events, with touch handling added separately and inconsistently, and the drag origin was calculated from the element rather than from the grab point.

The fix pattern: use Pointer Events with pointer capture, which unifies mouse, touch, and stylus into one code path. Then calculate the drag offset from where the pointer actually landed within the element, so the grabbed point stays under the pointer.

That second part is what "it jumps" almost always means. If a dragged element snaps so its center is at the cursor, the code is setting position from pointer coordinates without subtracting the initial offset within the element. It looks fine when you grab something near its center, which is what you do when testing your own feature.

5. Shrinking the Window Made Controls Disappear

The report: making the desktop window smaller lost UI elements entirely.

The layout had a desktop arrangement and a mobile arrangement, selected by viewport width. A narrow desktop window fell into a gap — too narrow for the desktop layout to fit, wide enough that the mobile layout did not engage. Controls overflowed their container and were clipped rather than reflowed.

The insight, which came from the user: a narrow desktop window should just use the mobile interface. The mobile layout already solves the narrow-viewport problem properly, with a drawer and a bottom sheet. There is no reason to maintain a third arrangement for the awkward middle.

We took this further later, consolidating the canvas menu into a single contextual drawer so there was one place controls lived rather than a native menu plus an app menu that disagreed with each other at narrow widths.

The rule: breakpoints should be chosen by whether the layout fits, not by whether the device is nominally a phone. A 500-pixel-wide desktop window has the same constraints as a phone and should get the same treatment.

What Ties These Together

Four of the five were invisible on a development machine — wide window, fast network, mouse input, permissions already granted, small test dataset.

The mitigations that actually work are unglamorous:

  • Pointer Events for anything draggable. Not mouse events with touch bolted on.
  • Client-side batching for every bounded endpoint, tested above the bound.
  • Breakpoints chosen by fit, not by device category.
  • No terminal state that depends on absent browser chrome.
  • Permission failures that name the platform-specific place to fix it.

And the one that finds the rest: use the product on a phone, with your real data, on a real network, as your primary device for a week. Every bug above was found that way. None were found by testing.

Open OmniCanvas on your phone and see how it holds up.

30 days free. No credit card required.

Try the Brainstorm Web template in OmniCanvas

Open a local canvas with the Brainstorm Web layout ready to go — no setup or account needed.

Use the Brainstorm Web Template

Start locally, then sign up only to sync — or explore the interactive demo first.