{"record":{"id":"7b4220ec6ce75b57","repo":"nodejs/node","slug":"key-must-be-ascii-string","errorCode":null,"errorMessage":"key must be ascii string","messagePattern":"key must be ascii string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/core/tree.js","lineNumber":31,"sourceCode":"  /** @type {null | TstNode} */\n  middle = null\n  /** @type {null | TstNode} */\n  right = null\n  /** @type {number} */\n  code\n  /**\n   * @param {string} key\n   * @param {any} value\n   * @param {number} index\n   */\n  constructor (key, value, index) {\n    if (index === undefined || index >= key.length) {\n      throw new TypeError('Unreachable')\n    }\n    const code = this.code = key.charCodeAt(index)\n    // check code is ascii string\n    if (code > 0x7F) {\n      throw new TypeError('key must be ascii string')\n    }\n    if (key.length !== ++index) {\n      this.middle = new TstNode(key, value, index)\n    } else {\n      this.value = value\n    }\n  }\n\n  /**\n   * @param {string} key\n   * @param {any} value\n   * @returns {void}\n   */\n  add (key, value) {\n    const length = key.length\n    if (length === 0) {\n      throw new TypeError('Unreachable')\n    }","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/core/tree.js#L13-L49","documentation":"Thrown by the TstNode constructor (the ternary search tree undici uses to index HTTP header field-names) when key.charCodeAt(index) > 0x7F. Per RFC 7230 §3.2.6, header field-names are restricted to the ASCII token grammar, so any non-ASCII byte in a name is rejected when the tree node is built.","triggerScenarios":"Constructing a Headers instance, or supplying a headers init object to fetch()/request, whose property name contains a non-ASCII character (e.g. 'X-Ünïcödé'), or inserting such a key into any structure backed by TstNode.","commonSituations":"Header names read from a Latin-1/UTF-8 config file without sanitization; copy/paste from docs introducing invisible non-ASCII characters; tooling that auto-generates header names from free-form input.","solutions":["Audit the headers object you pass and strip/replace any character above 0x7F in field names.","Validate dynamic header names against the RFC 7230 token grammar: /^[A-Za-z0-9!#$%&'*+\\-.^_`|~]+$/.","If you need Unicode metadata, put it in the header VALUE (which allows obs-text), never the field name.","Save source/config files as UTF-8 and re-check for accidental mojibake."],"exampleFix":"// before\nconst h = new Headers({ 'X-Custöm': 'val' })\n// after\nconst h = new Headers({ 'X-Custom': 'val' })","handlingStrategy":"validation","validationCode":"const HEADER_NAME_RE = /^[A-Za-z0-9!#$%&'*+\\-.^_`|~]+$/\nfunction safeHeaderName(name) {\n  if (typeof name !== 'string' || !HEADER_NAME_RE.test(name)) {\n    throw new TypeError(`Invalid header name: ${String(name)}`)\n  }\n  return name\n}","typeGuard":"function isValidHeaderName(name) {\n  return typeof name === 'string' && /^[A-Za-z0-9!#$%&'*+\\-.^_`|~]+$/.test(name)\n}","tryCatchPattern":null,"preventionTips":["Validate header names at the trust boundary where user input becomes a header.","Sanitize config-driven header keys before passing them to Headers.","Lint for non-ASCII characters in source-defined header names."],"tags":["headers","unicode","validation","undici"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}