grafana/k6 · error
sending key up: %w
Error message
sending key up: %w
What it means
Top-level wrapper returned by Keyboard.Up when the private k.up() fails. Like Down, it covers either an invalid key name for the active layout or a failed CDP Input.dispatchKeyEvent(KeyUp) call. Note the modifier bit and pressed-key bookkeeping happen before dispatch, so a failure here can leave keyboard modifier state inconsistent in the session.
Source
Thrown at internal/js/modules/k6/browser/common/keyboard.go:64
session: s,
pressedKeys: make(map[int64]struct{}),
layoutName: "us",
layout: keyboardlayout.GetKeyboardLayout("us"),
}
}
// Down sends a key down message to a session target.
func (k *Keyboard) Down(key string) error {
if err := k.down(key); err != nil {
return fmt.Errorf("sending key down: %w", err)
}
return nil
}
// Up sends a key up message to a session target.
func (k *Keyboard) Up(key string) error {
if err := k.up(key); err != nil {
return fmt.Errorf("sending key up: %w", err)
}
return nil
}
// Press sends a key press message to a session target.
// It delays the action if `Delay` option is specified.
// A press message consists of successive key down and up messages.
func (k *Keyboard) Press(key string, kbdOpts KeyboardOptions) error {
if err := k.comboPress(key, kbdOpts); err != nil {
return fmt.Errorf("pressing key: %w", err)
}
return nil
}
// InsertText inserts a text without dispatching key events.
func (k *Keyboard) InsertText(text string) error {
if err := k.insertText(text); err != nil {View on GitHub (pinned to 93accf6570)
Solutions
- Use valid US-layout key names ('Control', 'Shift', 'Enter')
- Keep down()/up() pairs adjacent with no navigation or page close between them
- Prefer press('Control+A') which handles the down/up pair atomically via comboPress
- Verify the page is open before the call
Example fix
// before
await page.keyboard.down('Control');
await page.click('#link'); // may navigate/close
await page.keyboard.up('Control');
// after
await page.keyboard.press('Control+A'); // atomic down+up Defensive patterns
Strategy: validation
Validate before calling
if (page.isClosed()) throw new Error('page closed before key up');
// validate key name against US-layout list (see isValidKey) before up() Type guard
function isValidKey(k) {
const VALID = new Set(['Enter','Backspace','Tab','Escape','ArrowUp','ArrowDown','ArrowLeft','ArrowRight','Home','End','PageUp','PageDown','Control','Shift','Alt','Meta']);
return VALID.has(k) || /^[a-zA-Z0-9]$/.test(k) || /^F([1-9]|1[0-2])$/.test(k);
} Try / catch
try {
await page.keyboard.up(key);
} catch (e) {
if (/not a valid key/.test(e.message)) throw new Error(`bad key name: ${key}`);
if (/dispatching key event up/.test(e.message)) await page.keyboard.press(key); // resync modifiers
else throw e;
} Prevention
- Use the same validated key name in down() and up()
- Prefer press() for atomic down/up pairs
- Never let navigation or page close happen between the pair
When it happens
Trigger: keyboard.up('Control') with a key name not in the layout; calling up() after the CDP session died (page closed, browser crashed); unbalanced down/up sequences where the second call races a navigation.
Common situations: Calling down() and up() around an await that navigates or closes the page; using localized key names from non-US keyboards.
Related errors
- sending key down: %w
- pressing key: %w
- inserting text: %w
- typing text: %w
- %q is not a valid key for layout %q
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/430824204cfb978c.
Report an issue: GitHub.