Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

@electric-sql/client throws SecurityError on import when the browser blocks site storage (typeof localStorage outside try)

Open Beginner friendly
#4,826 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@mohanedmoh is already working on this.

Since Oct 9, 2026.

  • #4827 by @mohanedmoh — open

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
web-dev

Research direction

The guard is in src/expired-shapes-cache.ts (save and load) and src/up-to-date-tracker.ts (save and load), where the typeof localStorage check sits before the try block. Reproduce by defining a throwing getter on globalThis.localStorage and importing the client. Done when the four methods put the availability check inside try and the import no longer throws, with working storage behaving as before.

Written by the indexing model from the issue text.

Description

Bug

When a browser blocks storage for a site (for example Chromium with cookies and site data not allowed for that site), reading window.localStorage throws:

SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.

ExpiredShapesCache and UpToDateTracker guard their storage access with if (typeof localStorage === 'undefined') return, placed before the try. typeof on a global accessor property still calls the getter, so the guard itself throws. Both classes are instantiated as module-level singletons (expiredShapesCache, upToDateTracker), so importing @electric-sql/client throws. The importing app's module graph fails before any of its own code runs, which leaves a blank page with no chance for an error boundary.

Seen in 1.5.24. The same code is in 1.5.28: src/expired-shapes-cache.ts (save and load) and src/up-to-date-tracker.ts (save and load).

Reproduction

Node (any runner):

Object.defineProperty(globalThis, 'localStorage', {
  configurable: true,
  get() {
    throw new DOMException('Access is denied for this document.', 'SecurityError')
  },
})
await import('@electric-sql/client') // throws from ExpiredShapesCache.load

Browser: Chromium with profile.default_content_setting_values.cookies = 2 in the profile's Preferences, then load any page that imports the client.

Suggested fix

Move the availability check inside the existing try in all four methods:

private load(): void {
  try {
    if (typeof localStorage === `undefined`) return
    const stored = localStorage.getItem(this.storageKey)
    if (stored) {
      this.data = JSON.parse(stored)
    }
  } catch {
    this.data = {}
  }
}

The catch blocks already treat storage errors as "no cache", so behavior with working storage stays the same. We currently carry this change as a pnpm patch over 1.5.24.

Possibly related: #3890 (custom localStorage implementation).

Dominant language
TypeScript
Stars
10.4k
Forks
391
Avg merge
22h 11m
Merged PRs (30d)
5

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from electric-sql/electric

All issues in electric-sql/electric

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.