[Bug] Background tokenizer throws "deadline is undefined" when the page has a non-spec requestIdleCallback shim (Safari 27 / iOS WKWebView)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 73/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- javascript, typescript
- Domain
- frontend
Research direction
Start in vs/base/common/async, where _runWhenIdle passes the callback to requestIdleCallback; the issue also identifies deadline reads in vs/editor/common/model/textModelTokens.ts and editor/browser/gpu/taskQueue.ts. Reproduce with the supplied shim before Monaco loads, then check that background tokenization no longer throws and continues making progress.
Written by the indexing model from the issue text.
Description
Reproducible in vscode.dev or in VS Code Desktop?
- Not reproducible in vscode.dev or VS Code Desktop
Reproducible in the monaco editor playground?
- Not reproducible in the playground (requires a third-party shim on the page, see below)
Monaco Editor version
0.57.0
Description
We're honestly in doubt about what exactly is going on, but our error reports keep showing an uncaught error from background tokenization, from quite a few different users:
TypeError: undefined is not an object (evaluating 'e.timeRemaining')
at DefaultBackgroundTokenizer._backgroundTokenizeWithDeadline (vs/editor/common/model/textModelTokens.js)
at <anonymous> (textModelTokens.js) // runWhenGlobalIdle((deadline) => …)
- Browsers: Safari 27.0 / 27.0.1 on macOS, and
WKWebViewon iOS 18.7. Nothing from Chromium or Firefox. - It started right after we upgraded from 0.24 to 0.57.
The runner is invoked with no arguments, and its direct caller is window.setTimeout. Stable Safari doesn't ship requestIdleCallback by default (WebKit #285049 was reverted), so this can't be the native implementation. Our best guess is that something on those clients injects requestIdleCallback/cancelIdleCallback shims shaped like cb => setTimeout(cb) into the page: an extension, a userscript, or an in-app browser. We couldn't identify which. That shape is common in the wild, since many hand-rolled "polyfills" never pass an IdleDeadline.
Since both globals exist, _runWhenIdle in vs/base/common/async takes the native branch and hands runner to the shim, which calls it without a deadline. The deadline is read in textModelTokens.ts and in editor/browser/gpu/taskQueue.ts.
Arguably this is the shim's fault, but a one-line guard would make the editor resilient to a pattern that shows up a lot.
Repro (derived from reading _runWhenIdle)
Before monaco loads, run:
window.requestIdleCallback = (cb) => setTimeout(cb);
window.cancelIdleCallback = clearTimeout;
Then open a model longer than the viewport and type. Every content change reschedules background tokenization, and the reschedule throws.
Possible fix
Normalize the deadline in the native branch of _runWhenIdle. This covers every consumer:
const handle = targetWindow.requestIdleCallback(
(deadline) => runner(deadline ?? { didTimeout: true, timeRemaining: () => 0 }),
typeof timeout === 'number' ? { timeout } : undefined,
);
With timeRemaining: () => 0, the tokenizer does one ~1ms slice per idle callback and reschedules itself, so it keeps making progress instead of throwing.
- Dominant language
- JavaScript
- Stars
- 46.9k
- Forks
- 4.2k
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 19
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/monaco-editor
-
[Bug] Why versions of marked and dompurify are fixed?May be free again A pull request for this issue was closed without being merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
microsoft/monaco-editor#5314 · 2 comments · 4 reactions ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 65/100
microsoft/monaco-editor#5193 ·
Maintainers usually reply within 1 day
-
[Bug] colorizeElement method doesn't color the whole text if domNode has more than one #text childOpen
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
microsoft/monaco-editor#4571 ·
Maintainers usually reply within 1 day
-
[Bug] Instructions for integrating with Vite don't workPossibly taken @aron-intframe claimed this 47 days ago. Openbug help wanted integration
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
microsoft/monaco-editor#4045 · 8 comments · 11 reactions ·
Maintainers usually reply within 1 day
-
documentation feature-request help wanted
Difficulty 2/5 Half a day Newbie friendliness 66/100
microsoft/monaco-editor#1761 · 1 comment ·
Maintainers usually reply within 1 day
All issues in microsoft/monaco-editor
Similar issues
-
neutral:fix
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
wazuh/wazuh-documentation#10611 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
remotion-dev/remotion#12905 ·
Maintainers usually reply within 1 day
-
enhancement websites
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
quarto-dev/quarto-cli#15255 · 1 comment ·
Maintainers usually reply within 1 day
-
Money fields reject amounts that aren't multiples of $500, so Find cliffs silently does nothingOpen
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
PolicyEngine/cliff-watch#44 ·