Description
Plane CE's lazy-loaded gantt-layout-loader chunk calls window.requestIdleCallback without feature detection or a polyfill. iOS WebKit (Safari, iOS Chrome, iOS Firefox — all WebKit-backed under Apple's App Store rules) has never implemented requestIdleCallback — open WebKit gap since 2016 (webkit.org#164193). The throw propagates up, React's error boundary catches it, and the user sees the generic "Looks like something went wrong" page on every issues-list / project view.
Steps to reproduce
- iPad (any iOS / iPadOS version), Chrome (CriOS user-agent — but iOS Safari and iOS Firefox would all fail the same way; see "Why the matrix is weird" below).
- Sign in to a Plane CE instance.
- Navigate to any project's
/projects/<uuid>/issues/ page.
- The full error boundary fires.
Console error (from Safari Web Inspector against the iPad)
TypeError: window.requestIdleCallback is not a function.
(In 'window.requestIdleCallback(()=>{h.current&&(S.current=`${h.current.offsetHeight}px`)})', 'window.requestIdleCallback' is undefined)
— gantt-layout-loader-BH8Iumhn.js:1:5524
React Router caught the following error during render
— componentDidCatch (chunk-EPOLDU6W-PsE1YSAx.js:4:2496)
[also] Minified React error #418 (hydration failed) and #423 (client-side recovery also failed)
— both downstream of the same throw.
Why the matrix is weird (and the cause is clear)
| Browser |
Result |
Why |
| iOS Chrome (CriOS) |
Error boundary |
UA hints route through the bundle that lazy-loads gantt-layout-loader → hits missing API |
| iOS Safari |
Works |
UA routes through a different bundle that doesn't load the gantt chunk |
| iOS Chrome with "Request Desktop Site" |
Works |
Desktop UA routes through the desktop bundle (gantt chunk apparently feature-detects or skips on the desktop layout calculator path) |
| macOS Safari / macOS Chrome |
Works |
Engines implement requestIdleCallback natively |
So the bug has been sitting hidden behind a UA-sniffing branch that only one of three iOS browser paths exercises.
Suggested fix
Either:
A — Polyfill requestIdleCallback once at app entry:
if (typeof window.requestIdleCallback !== 'function') {
window.requestIdleCallback = (cb) => {
const start = Date.now();
return setTimeout(() => cb({
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
}), 1);
};
window.cancelIdleCallback = (id) => clearTimeout(id);
}
B — Feature-detect inside gantt-layout-loader and fall back to setTimeout(fn, 0) for the height-measurement use case (which doesn't actually need idle-time semantics; it's just deferring a layout measurement).
Either is a few lines. (A) catches every other requestIdleCallback use in the codebase.
Environment
- Plane CE v1.3.1 (self-hosted, full upstream image set)
- Client: iPad (any), Chrome on iOS / iOS WebKit
Description
Plane CE's lazy-loaded
gantt-layout-loaderchunk callswindow.requestIdleCallbackwithout feature detection or a polyfill. iOS WebKit (Safari, iOS Chrome, iOS Firefox — all WebKit-backed under Apple's App Store rules) has never implementedrequestIdleCallback— open WebKit gap since 2016 (webkit.org#164193). The throw propagates up, React's error boundary catches it, and the user sees the generic "Looks like something went wrong" page on every issues-list / project view.Steps to reproduce
/projects/<uuid>/issues/page.Console error (from Safari Web Inspector against the iPad)
Why the matrix is weird (and the cause is clear)
requestIdleCallbacknativelySo the bug has been sitting hidden behind a UA-sniffing branch that only one of three iOS browser paths exercises.
Suggested fix
Either:
A — Polyfill
requestIdleCallbackonce at app entry:B — Feature-detect inside
gantt-layout-loaderand fall back tosetTimeout(fn, 0)for the height-measurement use case (which doesn't actually need idle-time semantics; it's just deferring a layout measurement).Either is a few lines. (A) catches every other
requestIdleCallbackuse in the codebase.Environment