Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug] Safari: installWebKitWriteTextWorkaround leaks an unhandled Canceled: Canceled rejection on every click/keydown #5458

Description

Reproducible in vscode.dev or in VS Code Desktop?

Not applicable — the code path only runs on Safari/WebKit (if (isSafari || isWebkitWebView)), so it cannot occur in Electron, and vscode.dev would need to be opened in Safari specifically.

Description

BrowserClipboardService.installWebKitWriteTextWorkaround produces an unhandled promise rejection that reaches window.onunhandledrejection, reported by error trackers as:

Canceled: Canceled
  at DeferredPromise.cancel (vs/base/common/async.js)
  at handler (vs/platform/clipboard/browser/clipboardService.js)

Cause

The workaround installs a click and keydown listener that, on every event, creates a DeferredPromise and cancels the previous one:

const handler = () => {
    const currentWritePromise = new DeferredPromise();
    // Cancel the previous promise since we just created a new one in response to this new event
    if (this.webKitPendingClipboardWritePromise && !this.webKitPendingClipboardWritePromise.isSettled) {
        this.webKitPendingClipboardWritePromise.cancel();
    }
    this.webKitPendingClipboardWritePromise = currentWritePromise;
    getActiveWindow().navigator.clipboard.write([new ClipboardItem({
        'text/plain': currentWritePromise.p,
    })]).catch(async (err) => { ... });
};

DeferredPromise.cancel() rejects .p with a CancellationError. The only consumer of .p is the ClipboardItem constructor, which does not attach a rejection handler to it, so nothing ever observes that rejection. The .catch(...) attached to navigator.clipboard.write(...) handles a different promise — the write's own — and does not mark .p as handled.

The cancellation itself is intended behaviour, so this is pure noise: nothing is broken when it fires, and clipboard writes keep working. But because a click or keydown anywhere in the container triggers it, it fires constantly for Safari users and drowns real errors in telemetry.

Suggested fix

Observe the rejection where the deferred is created, leaving the promise handed to ClipboardItem (and the isRejected check the surrounding catch relies on) untouched:

 const currentWritePromise = new DeferredPromise();
+// `ClipboardItem` does not attach a rejection handler to the promise it is given, so the
+// cancellation below would surface as an unhandled rejection on the window.
+currentWritePromise.p.catch(() => { });
 // Cancel the previous promise since we just created a new one in response to this new event
 if (this.webKitPendingClipboardWritePromise && !this.webKitPendingClipboardWritePromise.isSettled) {
     this.webKitPendingClipboardWritePromise.cancel();
 }

Environment

  • monaco-editor-core 0.52.2; the code is unchanged in 0.56.0 and in microsoft/vscode main
  • Safari 26.6, macOS

Possibly the same root cause

Several open reports describe Canceled: Canceled unhandled rejections triggered by clipboard interaction, none of which names this code path: #4389 (holding Cmd+V), #4776 (rapid pasting). #4389 is marked "not reproducible in vscode.dev or VS Code Desktop", which is consistent with a Safari-only path.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions