grafana/k6 · error

%q is not a valid key for layout %q

Error message

%q is not a valid key for layout %q

What it means

Validation error from Keyboard.down(): the requested key string, after platformSpecificResolution, does not exist in the active keyboard layout's ValidKeys set (default layout 'us'). No CDP call is made — the request is rejected locally before any event is dispatched. This is the down-path variant using %q formatting.

Source

Thrown at internal/js/modules/k6/browser/common/keyboard.go:105

// Type sends a press message to a session target for each character in text.
// It delays the action if `Delay` option is specified.
//
// It sends an insertText message if a character is not among
// valid characters in the keyboard's layout.
func (k *Keyboard) Type(text string, kbdOpts KeyboardOptions) error {
	if err := k.typ(text, kbdOpts); err != nil {
		return fmt.Errorf("typing text: %w", err)
	}
	return nil
}

func (k *Keyboard) down(key string) error {
	key = k.platformSpecificResolution(key)

	keyInput := keyboardlayout.KeyInput(key)
	if _, ok := k.layout.ValidKeys[keyInput]; !ok {
		return fmt.Errorf("%q is not a valid key for layout %q", key, k.layoutName)
	}

	keyDef := k.keyDefinitionFromKey(keyInput)
	k.modifiers |= k.modifierBitFromKeyName(keyDef.Key)
	text := keyDef.Text

	k.pressedKeysMu.Lock()
	_, autoRepeat := k.pressedKeys[keyDef.KeyCode]
	k.pressedKeys[keyDef.KeyCode] = struct{}{}
	k.pressedKeysMu.Unlock()

	keyType := input.KeyDown
	if text == "" {
		keyType = input.KeyRawDown
	}

	action := input.DispatchKeyEvent(keyType).
		WithModifiers(input.Modifier(k.modifiers)).

View on GitHub (pinned to 93accf6570)

Solutions

  1. Use the exact key names from the US layout: Enter, Backspace, Delete, Tab, Escape, ArrowUp/Down/Left/Right, Home, End, PageUp, PageDown, Control, Shift, Alt, Meta, F1-F12, single characters
  2. Match casing exactly — 'control' is rejected, 'Control' is valid
  3. For characters outside the layout use insertText()
  4. Check the layout package's ValidKeys (keyboardlayout.GetKeyboardLayout('us')) for the authoritative list

Example fix

// before
await page.keyboard.down('Return');
await page.keyboard.up('Return');

// after
await page.keyboard.down('Enter');
await page.keyboard.up('Enter');
Defensive patterns

Strategy: validation

Validate before calling

const VALID_KEYS = new Set(['Enter','Backspace','Delete','Tab','Escape','ArrowUp','ArrowDown','ArrowLeft','ArrowRight','Home','End','PageUp','PageDown','Control','Shift','Alt','Meta',' ','Add','Subtract','Multiply','Divide','Separator','Decimal','F1','F2','F3','F4','F5','F6','F7','F8','F9','F10','F11','F12']);
function isValidKeyName(k) {
  return VALID_KEYS.has(k) || /^[a-zA-Z0-9]$/.test(k);
}
if (!isValidKeyName(key)) throw new Error(`unsupported key: ${key}`);

Type guard

function isValidKeyName(k) {
  const VALID = new Set(['Enter','Backspace','Delete','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.down(key);
} catch (e) {
  if (/is not a valid key for layout/.test(e.message)) {
    // map common OS names to CDP names and retry once
    const alias = { Return: 'Enter', Backtab: 'Tab', Cmd: 'Meta', Ctrl: 'Control', Esc: 'Escape' }[key];
    if (alias) await page.keyboard.down(alias); else throw e;
  } else throw e;
}

Prevention

When it happens

Trigger: keyboard.down('Return') (correct name is 'Enter'); down('backspace') — names are case-sensitive; down('é') — not a US-layout key; down('Cmd') — not valid on the 'us' layout used by CDP (use 'Meta').

Common situations: Porting scripts from OS automation tools (xdotool 'Return', Windows VK names); non-US keyboard muscle memory; assuming lowercase modifier names work.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/e9713d90c24ea196. Report an issue: GitHub.