Skip to content

Pasting with the caret on a quote element crashes with Lexical error #211/#212#1109

Open
jorgemanrubia wants to merge 1 commit into
mainfrom
sentry-lexical-error-211
Open

Pasting with the caret on a quote element crashes with Lexical error #211/#212#1109
jorgemanrubia wants to merge 1 commit into
mainfrom
sentry-lexical-error-211

Conversation

@jorgemanrubia

@jorgemanrubia jorgemanrubia commented Jun 10, 2026

Copy link
Copy Markdown
Member

Fixes BC3-JS-N7AZ — 884 events / 537 users since May 26 (180 / 138 in the last 3 days). Card: https://app.basecamp.com/2914079/buckets/41746046/card_tables/cards/9982982415

What it fixes

Pasting with the caret sitting on the blockquote element itself (an element point on the QuoteNode, e.g. after clicking in the gap between two paragraphs inside a quote) crashed and lost the paste. Every Sentry event goes through the same path: Contents#insertDOMinsertAtCursorRangeSelection.insertNodes, throwing Lexical error #211 ("Expected node QuoteNode of type quote to have a block ElementNode ancestor") for inline content or #212 ("…to have a block ancestor") for block content.

How

Lexical's RangeSelection.insertNodes requires every selection point to have a block ancestor with inline children (INTERNAL_$isBlock). A lexxy quote always holds paragraphs ($ensureQuoteHasParagraphChild), so an element point on the quote has no such ancestor — the quote fails the leaf-block check and its parent is the root.

A new BlockContainerNodeInserter handles range selections where a point sits on a container of block nodes: it normalizes the selection down to a leaf position ($normalizeSelection__EXPERIMENTAL, the same descent Lexical applies to DOM selections) and then delegates to the regular insertNodes.

Includes Playwright regression tests at test/browser/tests/paste/paste_with_caret_on_quote.test.js covering both the #211 (inline paste) and #212 (block paste) variants. They place the caret as an element point on the quote and drive a real clipboard paste. Verified red/green: with src/ reverted to main both tests fail (2 failed); with the fix both pass (2 passed).

Copilot AI review requested due to automatic review settings June 10, 2026 17:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a Lexical crash when pasting while the caret is positioned on the QuoteNode element itself (an element-point selection on a block-container node), by normalizing such range selections down to a leaf position before delegating to Lexical’s RangeSelection.insertNodes.

Changes:

  • Add a BlockContainerNodeInserter to detect range selections whose anchor/focus are element points on a container of block children and normalize the selection before insertion.
  • Add vitest regression coverage for both the inline and block paste crash variants (Lexical invariants #211 and #212).

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
test/javascript/unit/editor/paste_with_caret_on_quote.test.js Adds regression tests ensuring paste into a quote element-point selection no longer crashes and preserves inserted content.
src/editor/contents/node_inserter.js Introduces a new inserter that normalizes range selections on block containers before calling insertNodes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Lexical's RangeSelection.insertNodes requires every selection point to
have a block ancestor with inline children. When the caret sits on the
blockquote element itself (an element point on the QuoteNode), a quote
holding paragraphs has no such ancestor and Lexical throws invariant
errors #211 (inline content) or #212 (block content), losing the paste.

Normalize such selections down to a leaf position before inserting.
@jorgemanrubia jorgemanrubia force-pushed the sentry-lexical-error-211 branch from 86e9d86 to 5e10db9 Compare June 10, 2026 19:02
@jorgemanrubia jorgemanrubia marked this pull request as draft June 10, 2026 19:02
@jorgemanrubia jorgemanrubia marked this pull request as ready for review June 11, 2026 05:24
@romansklenar

Copy link
Copy Markdown

Another lexxy consumer here (a Rails app, lexxy 0.9.12.beta) — confirming this #212 isn't BC3-specific; we see it in production too.

Our path matches yours exactly (Contents#insertDOMinsertAtCursorRangeSelection.insertNodes), but the entry point is a markdown paste rather than a manual element-point-on-quote: Clipboard#pasteMarkdowncontents.insertDOM(doc, { tag: PASTE_TAG })insertAtCursorinsertNodes#212 (message args …At… quote, so a QuoteNode is the container point). Real user paste, Chrome 149 / macOS.

Since both entry points funnel through the same insertNodes, your BlockContainerNodeInserter selection-normalization should cover the markdown-paste case too — just flagging it as a second real-world trigger in case the regression tests are worth extending to a markdown paste onto a quote. Happy to share more of the stack if useful.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants