{"record":{"id":"382b1095f885d042","repo":"SeleniumHQ/selenium","slug":"key-input-is-not-a-single-code-point-key","errorCode":null,"errorMessage":"key input is not a single code point: ${key}","messagePattern":"key input is not a single code point: (.+?)","errorType":"validation","errorClass":"InvalidArgumentError","httpStatus":400,"severity":"error","filePath":"javascript/selenium-webdriver/lib/input.js","lineNumber":258,"sourceCode":"}\n\n/**\n * @param {(string|Key|number)} key\n * @return {string}\n * @throws {!(InvalidArgumentError|RangeError)}\n */\nfunction checkCodePoint(key) {\n  if (typeof key === 'number') {\n    return String.fromCodePoint(key)\n  }\n\n  if (typeof key !== 'string') {\n    throw new InvalidArgumentError(`key is not a string: ${key}`)\n  }\n\n  key = key.normalize()\n  if (Array.from(key).length !== 1) {\n    throw new InvalidArgumentError(`key input is not a single code point: ${key}`)\n  }\n  return key\n}\n\n/**\n * Keyboard input device.\n *\n * @final\n * @see <https://www.w3.org/TR/webdriver/#dfn-key-input-source>\n */\nclass Keyboard extends Device {\n  /** @param {string} id the device ID. */\n  constructor(id) {\n    super(Device.Type.KEY, id)\n  }\n\n  /**\n   * Generates a key down action.","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/javascript/selenium-webdriver/lib/input.js#L240-L276","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nawait driver.actions().keyDown('ab').perform(); // throws\n\n// after\nfor (const ch of [...'ab']) {\n  await driver.actions().keyDown(ch).keyUp(ch).perform();\n}","handlingStrategy":"validation","validationCode":"function assertSingleCodePoint(key) {\n  if (typeof key === 'number') return; // number is accepted by the helper\n  if (typeof key !== 'string') throw new TypeError('key must be string or number');\n  const norm = key.normalize();\n  if ([...norm].length !== 1) {\n    throw new Error(`key is not a single code point: ${JSON.stringify(key)}`);\n  }\n}\n// call before actions.keyDown(key) etc.","typeGuard":"function isSingleCodePoint(key) {\n  return typeof key === 'number' || (typeof key === 'string' && [...key.normalize()].length === 1);\n}","tryCatchPattern":"try {\n  await driver.actions().keyDown(maybeBadKey).perform();\n} catch (e) {\n  if (e.name === 'InvalidArgumentError' && /single code point/.test(e.message)) {\n    // split into code points and retry each\n    for (const ch of [...maybeBadKey.normalize()]) {\n      await driver.actions().keyDown(ch).keyUp(ch).perform();\n    }\n  } else throw e;\n}","preventionTips":["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."],"tags":["input","keyboard","unicode","validation","invalid-argument"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}