{"record":{"id":"86fd34881b1df3a3","repo":"grafana/k6","slug":"releasing-the-mouse-button-on-x-f-y-f-w","errorCode":null,"errorMessage":"releasing the mouse button on x:%f y:%f: %w","messagePattern":"releasing the mouse button on x:(.+?) y:(.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/mouse.go","lineNumber":100,"sourceCode":"\treturn nil\n}\n\nfunc (m *Mouse) down(opts *MouseDownUpOptions) error {\n\tm.button = input.MouseButton(opts.Button)\n\taction := input.DispatchMouseEvent(input.MousePressed, m.x, m.y).\n\t\tWithButton(input.MouseButton(opts.Button)).\n\t\tWithModifiers(input.Modifier(m.keyboard.modifiers)).\n\t\tWithClickCount(opts.ClickCount)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\treturn fmt.Errorf(\"mouse down: %w\", err)\n\t}\n\treturn nil\n}\n\n// Up will trigger a MouseUp event in the browser.\nfunc (m *Mouse) Up(opts *MouseDownUpOptions) error {\n\tif err := m.up(opts); err != nil {\n\t\treturn fmt.Errorf(\"releasing the mouse button on x:%f y:%f: %w\", m.x, m.y, err)\n\t}\n\treturn nil\n}\n\nfunc (m *Mouse) up(opts *MouseDownUpOptions) error {\n\tm.button = input.None\n\taction := input.DispatchMouseEvent(input.MouseReleased, m.x, m.y).\n\t\tWithButton(input.MouseButton(opts.Button)).\n\t\tWithModifiers(input.Modifier(m.keyboard.modifiers)).\n\t\tWithClickCount(opts.ClickCount)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\treturn fmt.Errorf(\"mouse up: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Move will trigger a MouseMoved event in the browser.","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/mouse.go#L82-L118","documentation":"Thrown by Mouse.Up() when the internal m.up() fails. Up() dispatches Input.dispatchMouseEvent(mouseReleased) at the mouse's current coordinates (m.x, m.y). It fails when the DevTools session is gone (page closed, target crashed, browser exited) between the down and the up, or the protocol call is rejected.","triggerScenarios":"mouse.up() called after the page navigated or closed following mouse.down(); browser/target crash while a press-hold gesture is in flight; dispatch rejected on a dead session.","commonSituations":"Drag-and-drop simulations where mousedown opens a popup or navigation that invalidates the session; long mouse-hold sleeps exceeding page lifetime; tests resuming gestures on a re-created page (mouse state is per Mouse instance).","solutions":["Keep down/move/up in one uninterrupted sequence without navigation or long sleeps in between","Check page.isClosed() before mouse.up() and fail fast with a clear message","Re-create the page and restart the whole gesture (not just up) if the session dropped","Avoid mousedown handlers that destroy the page mid-gesture"],"exampleFix":"// before\nawait page.mouse.down();\nawait sleep(10); // page may close here\nawait page.mouse.up();\n\n// after\nawait page.mouse.down();\nawait page.mouse.move(320, 240, { steps: 3 });\nawait page.mouse.up(); // no gaps that could close the page","handlingStrategy":"try-catch","validationCode":"if (page.isClosed()) throw new Error('page closed before release');\nawait page.mouse.up();","typeGuard":null,"tryCatchPattern":"try {\n  await page.mouse.up();\n} catch (e) {\n  if (/target closed|session/i.test(e.message)) {\n    // gesture unrecoverable on this page; recreate page and restart gesture\n    throw new Error('session lost between down and up');\n  }\n  throw e;\n}","preventionTips":["Finish drag gestures before navigating","Avoid long sleeps between down and up","Design app interactions so mousedown does not close the page"],"tags":["browser","mouse","cdp","drag"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}