Replies: 3 comments
-
|
I'm going to convert this to a discussion because it's not really a bug in RR but a false positive in these content blockers. If enough folks express interest, we can use the RFC as a way to change the underlying implementation or open up a configureable approach. |
Beta Was this translation helpful? Give feedback.
-
|
@actraiser is this consistent? does the users cant use the app at all or they get this error from time to time? |
Beta Was this translation helpful? Give feedback.
-
|
It's fully consistent. Content blockers use static pattern-matching rules at the WebKit network layer, so every .data request is blocked deterministically. For affected users, the initial SSR page load works, but every subsequent client-side navigation fails 100% of the time. There's no intermittent behavior: either the user has content blocker and all SPA navigations break, or they don't and everything works. Users tested with Crystal, AdBlock Pro, and 1Blocker, all consistent. Results may vary with other content blockers depending on their rule sets. This isn't an isolated issue. Other frameworks have dealt with similar false positives from iOS content blockers: Rollup/Vite had hash-based chunk names blocked by EasyList rules (rollup/rollup#5374), SvelteKit had ad blockers crashing entire apps by blocking single component imports (sveltejs/kit#10118), and Angular reported FetchEvent errors tied to iOS content restrictions (angular/angular#50378). WebKit itself has open bugs about lacking any developer-facing callback when a request is blocked (WebKit Bug #152598), making graceful handling impossible. The key difference is that other frameworks (Next.js, Nuxt, SvelteKit) use _-prefixed internal paths that content blockers recognize as framework internals, while React Router's .data suffix on real route URLs looks indistinguishable from a tracking endpoint to pattern-matching rules. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
React Router v7's single fetch mechanism appends
.datato route URLs for client-side navigation data fetching (e.g.,/post/22378.data?_routes=root,routes/public/realm/...). iOS Safari content blockers (Crystal, AdBlock Pro, and others) block these requests because the URL pattern resembles data-collection or tracking endpoints. This causes aTypeError: Load failed, which triggers the ErrorBoundary and crashes the app for affected users.Full SSR page loads work fine because no
.datarequest is needed. Only client-side SPA navigations break.This affects any React Router v7 SSR app used by iOS Safari users who have a content blocker installed.
Steps to Reproduce
.datarequest is blocked. The app crashes into the ErrorBoundary.Error Logs (Safari Web Inspector)
Why This Happens
iOS content blockers use the WebKit Content Blocker API, which applies pattern-matching JSON rules at the network layer before any JavaScript executes. This means:
TypeError: Load failed.The
.dataextension and the_routesquery parameter with comma-separated route names closely resemble analytics/tracking payloads. Content blocker rule authors write broad patterns to catch data-collection endpoints, and.dataURLs match those patterns.Comparison with Other Frameworks
Other meta-frameworks use URL patterns that content blockers do not flag, because they use
_prefixed path segments that are recognized as framework internals:/_next/data/buildId/page.json/_payload/page/__data.json/some/route.data?_routes=...The key difference: other frameworks place data fetches under a clearly internal,
_prefixed path. React Router appends.dataas a file extension to the actual route URL, which looks indistinguishable from a tracking request to pattern-matching content blockers.Suggested Fix
react-router.config.ts)._prefixed path pattern that content blockers recognize as a framework internal, for example:/_data/some/routeor/__data/some/route.json.The
.datasuffix is currently hardcoded insingleFetchUrl()in the router source. There is no config option to change it.Workaround
Currently, the only workaround for affected users is to disable their content blocker for the specific site, or disable it entirely. This is not a reasonable expectation for end users who may not understand why the app is broken.
There is no application-level workaround available to developers, since the block happens at WebKit's network layer before JavaScript can intervene.
Environment
Beta Was this translation helpful? Give feedback.
All reactions