Skip to content

fix(drag): wrap setPointerCapture in try/catch to handle InvalidPointerId#706

Open
EduardF1 wants to merge 2 commits into
pmndrs:mainfrom
EduardF1:fix/drag-setpointercapture-invalidpointerid
Open

fix(drag): wrap setPointerCapture in try/catch to handle InvalidPointerId#706
EduardF1 wants to merge 2 commits into
pmndrs:mainfrom
EduardF1:fix/drag-setpointercapture-invalidpointerid

Conversation

@EduardF1

Copy link
Copy Markdown

Problem

DragEngine.pointerDown calls setPointerCapture unguarded:

if (config.pointerCapture) {
  ;(event.target as HTMLElement).setPointerCapture(event.pointerId)
}

Browsers throw a DOMException: InvalidPointerId when the pointer id is no longer valid by the time this runs — e.g. the pointer was released between event dispatch and the capture call during rapid touch interactions or certain browser quirks. The exception aborts pointerDown, so the drag gesture never starts.

The symmetric releasePointerCapture call in pointerUp is already wrapped in try/catch for exactly this reason — this PR adds the missing guard on the other side.

Fix

Wrap setPointerCapture in try/catch, consistent with the existing releasePointerCapture handling. The drag proceeds without pointer capture instead of throwing.

Tests

Adds a regression test in test/drag.test.tsx that makes setPointerCapture throw InvalidPointerId and asserts the drag still starts (active/dragging true, onDragStart fired). Verified it fails on main and passes with the fix.

  • pnpm jest — 218 passed (8 suites), including the new test
  • eslint packages/core/src/engines/DragEngine.ts — clean

Includes a changeset (@use-gesture/core patch).

Fixes #701

Note: supersedes my earlier #705, which was unmergeable because the branch accidentally included a large amount of unrelated build output. This is a clean re-submission containing only the logic fix, the regression test, and a changeset.

…erId

DragEngine.pointerDown called setPointerCapture unguarded, which throws a
DOMException (InvalidPointerId) when the pointer id is no longer valid by the
time the engine handles the event (e.g. the pointer was released between event
dispatch and the capture call during rapid touch interactions). This aborted
the drag gesture. Wrap the call in try/catch so the drag proceeds without
pointer capture, mirroring the already-guarded releasePointerCapture in
pointerUp. Adds a regression test.

Fixes pmndrs#701

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 38e5eb1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@use-gesture/core Patch
@use-gesture/react Patch
@use-gesture/vanilla Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codesandbox-ci

Copy link
Copy Markdown

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 38e5eb1:

Sandbox Source
gesture-drag Configuration
gesture-drag-target Configuration
gesture-nested Configuration
gesture-drag-vanilla Configuration
gesture-move Configuration
gesture-pinch Configuration
gesture-multiple-pinch Configuration
gesture-three Configuration
gesture-card-zoom Configuration
gesture-viewpager Configuration

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.

[Bug] setPointerCapture in pointerDown should be wrapped in try-catch

1 participant