A swallowed storage write needs an in-memory copy, or the next read contradicts it
Fact
Wrapping a storage call in try/catch stops it from throwing; it does not make the write happen. localStorage throws on every access in private-browsing modes, under blocked-cookie settings, and from opaque origins such as data: and sandboxed frames — so a helper that catches and returns turns a failed write into a silent one.
The bug appears at the next read. Code that treats the store as its source of truth re-reads the key, gets the pre-write value, and contradicts the write it just reported as successful — inside a single session, with no error anywhere.
Why it matters
The failure lands on whatever the value gates, so it presents as broken logic rather than broken persistence: a flag that will not set, a step that reopens after being completed, a preference that reverts the moment it is read back.
It also survives testing, because development happens in an ordinary window where the writes succeed. Only the users whose storage is unavailable see it, and for them the feature is not degraded but wrong.
How to apply
- Keep the value in memory and treat storage as write-through: read it once to seed, serve every subsequent read from the field, and persist on change.
- Then a storage failure costs only persistence across reloads, which is the honest consequence, instead of corrupting the running session.
- Distinguish "absent" from "zero" when seeding.
JSON.parse(null)isnulland a stored0is falsy, sostored || DEFAULTsilently resets a legitimate zero; test the type or compare againstnullexplicitly. - Probe once at startup if the UI should say so, rather than at each call site.