{"record":{"id":"20cb7d6fc9b7e408","repo":"grafana/k6","slug":"dispatching-key-event-up-w","errorCode":null,"errorMessage":"dispatching key event up: %w","messagePattern":"dispatching key event up: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/keyboard.go","lineNumber":160,"sourceCode":"\tkeyInput := keyboardlayout.KeyInput(key)\n\tif _, ok := k.layout.ValidKeys[keyInput]; !ok {\n\t\treturn fmt.Errorf(\"'%s' is not a valid key for layout '%s'\", key, k.layoutName)\n\t}\n\n\tkeyDef := k.keyDefinitionFromKey(keyInput)\n\tk.modifiers &= ^k.modifierBitFromKeyName(keyDef.Key)\n\tk.pressedKeysMu.Lock()\n\tdelete(k.pressedKeys, keyDef.KeyCode)\n\tk.pressedKeysMu.Unlock()\n\n\taction := input.DispatchKeyEvent(input.KeyUp).\n\t\tWithModifiers(input.Modifier(k.modifiers)).\n\t\tWithKey(keyDef.Key).\n\t\tWithWindowsVirtualKeyCode(keyDef.KeyCode).\n\t\tWithCode(keyDef.Code).\n\t\tWithLocation(keyDef.Location)\n\tif err := action.Do(cdp.WithExecutor(k.ctx, k.session)); err != nil {\n\t\treturn fmt.Errorf(\"dispatching key event up: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *Keyboard) insertText(text string) error {\n\taction := input.InsertText(text)\n\tif err := action.Do(cdp.WithExecutor(k.ctx, k.session)); err != nil {\n\t\treturn fmt.Errorf(\"inserting text: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (k *Keyboard) keyDefinitionFromKey(key keyboardlayout.KeyInput) keyboardlayout.KeyDefinition {\n\tshift := k.modifiers & ModifierKeyShift\n\n\t// Find directly from the keyboard layout\n\tsrcKeyDef, ok := k.layout.Keys[key]","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/keyboard.go#L142-L178","documentation":"Thrown by Keyboard.up() when the CDP Input.dispatchKeyEvent(KeyUp) action fails after validation passed. The modifier state and pressedKeys map are already updated before dispatch, so on failure the tracked modifier bit for the key has been cleared locally even though no key-up reached the page — later events may carry wrong modifiers if the session survives.","triggerScenarios":"up('Shift') after the page closed between down and up; target crash before the key-up; context canceled by a timeout exactly between the paired events.","commonSituations":"down/up pairs straddling an await that navigates or closes the page; long-running hold-key interactions under tight timeouts.","solutions":["Keep down()/up() adjacent; use press() for atomic pairs","Check page.isClosed() before up()","On failure in a surviving session, send a fresh down/up press() to resynchronize modifier state","Raise the timeout if DeadlineExceeded is the wrapped cause"],"exampleFix":"// before\nawait page.keyboard.down('Shift');\nawait page.goto(url);              // navigation between the pair\nawait page.keyboard.up('Shift');\n\n// after\nawait page.goto(url);\nawait page.keyboard.press('Shift+F10'); // atomic combo after navigation","handlingStrategy":"try-catch","validationCode":"if (page.isClosed()) throw new Error('page closed before key up');","typeGuard":null,"tryCatchPattern":"try {\n  await page.keyboard.up(key);\n} catch (e) {\n  if (/dispatching key event up/.test(e.message) && !page.isClosed()) {\n    await page.keyboard.press(key); // resync modifier state after failed up\n  } else throw e;\n}","preventionTips":["Never navigate or close between down() and up()","Use press() for atomic pairs","After an up() failure, re-press the key to clear stuck modifiers"],"tags":["browser","keyboard","cdp","session-closed","state-desync"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}