SeleniumHQ/selenium · error · InvalidArgumentError
key input is not a single code point: ${key}
Error message
key input is not a single code point: ${key} What it means
Thrown by the internal checkCodePoint() helper when a key argument passed to a keyboard input action does not reduce to exactly one Unicode code point after NFC normalization. The WebDriver input protocol operates on single code units/code points, so multi-character keys are rejected at argument validation time. It is an InvalidArgumentError (HTTP 400 / invalid argument wire-level error), surfaced through selenium-webdriver's input device layer.
Source
Thrown at javascript/selenium-webdriver/lib/input.js:258
}
/**
* @param {(string|Key|number)} key
* @return {string}
* @throws {!(InvalidArgumentError|RangeError)}
*/
function checkCodePoint(key) {
if (typeof key === 'number') {
return String.fromCodePoint(key)
}
if (typeof key !== 'string') {
throw new InvalidArgumentError(`key is not a string: ${key}`)
}
key = key.normalize()
if (Array.from(key).length !== 1) {
throw new InvalidArgumentError(`key input is not a single code point: ${key}`)
}
return key
}
/**
* Keyboard input device.
*
* @final
* @see <https://www.w3.org/TR/webdriver/#dfn-key-input-source>
*/
class Keyboard extends Device {
/** @param {string} id the device ID. */
constructor(id) {
super(Device.Type.KEY, id)
}
/**
* Generates a key down action.View on GitHub (pinned to aa36b38e69)
Solutions
- Split the input into individual code points and iterate: [...str] in JS yields code points; feed one per action.
- Use String.fromCodePoint(codePointNumber) when you have a numeric code point, or pass the number directly (the helper accepts numbers).
- Verify the value with [...key].length === 1 before building the action; log the offending key.
- If you genuinely need a multi-character sequence, send each as a separate key action or use element.sendKeys(text) which handles sequences.
- Check that you are not accidentally passing a Key.* constant that is itself multi-codepoint (rare, but possible with custom constants).
Example fix
// before
await driver.actions().keyDown('ab').perform(); // throws
// after
for (const ch of [...'ab']) {
await driver.actions().keyDown(ch).keyUp(ch).perform();
} Defensive patterns
Strategy: validation
Validate before calling
function assertSingleCodePoint(key) {
if (typeof key === 'number') return; // number is accepted by the helper
if (typeof key !== 'string') throw new TypeError('key must be string or number');
const norm = key.normalize();
if ([...norm].length !== 1) {
throw new Error(`key is not a single code point: ${JSON.stringify(key)}`);
}
}
// call before actions.keyDown(key) etc. Type guard
function isSingleCodePoint(key) {
return typeof key === 'number' || (typeof key === 'string' && [...key.normalize()].length === 1);
} Try / catch
try {
await driver.actions().keyDown(maybeBadKey).perform();
} catch (e) {
if (e.name === 'InvalidArgumentError' && /single code point/.test(e.message)) {
// split into code points and retry each
for (const ch of [...maybeBadKey.normalize()]) {
await driver.actions().keyDown(ch).keyUp(ch).perform();
}
} else throw e;
} Prevention
- Always iterate input with [...str] to get code points, never str.split('').
- Prefer element.sendKeys(fullText) for sequences instead of per-key actions.
- Validate keys once at the boundary where they enter your code from config/user input.
When it happens
Trigger: Calling actions.keyDown(key)/keyUp(key)/sendKeys with a string that contains more than one code point (e.g. 'ab', an emoji+VS16 sequence, or a grapheme cluster that stays multi-codepoint after normalize()). Also triggered when a key value resolves to an empty string or a multi-codepoint Key constant is misused. Single characters like 'a', a surrogate-pair emoji that is exactly one code point, or a numeric code point (e.g. 0x1F600) pass.
Common situations: Passing the user's typed text as a single 'key' instead of one character at a time; copy-pasting a key from a doc that included a combining mark; sending a multi-codepoint symbol (e.g. flags '🇺🇸' = two regional indicators) as a keystroke; version upgrades where Key.* constants changed representation.
Related errors
- key is not a string: ${key}
- Invalid drag target; must specify a WebElement or {x, y} off
- Unexpected compiled output format. Expected it to start with
- Unexpected compiled output format. Expected it to start with
- Unexpected compiled output format. Expected it to start with
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/382b1095f885d042.
Report an issue: GitHub.