nodejs/node · error · TypeError
key must be ascii string
Error message
key must be ascii string
What it means
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.
Source
Thrown at deps/undici/src/lib/core/tree.js:31
/** @type {null | TstNode} */
middle = null
/** @type {null | TstNode} */
right = null
/** @type {number} */
code
/**
* @param {string} key
* @param {any} value
* @param {number} index
*/
constructor (key, value, index) {
if (index === undefined || index >= key.length) {
throw new TypeError('Unreachable')
}
const code = this.code = key.charCodeAt(index)
// check code is ascii string
if (code > 0x7F) {
throw new TypeError('key must be ascii string')
}
if (key.length !== ++index) {
this.middle = new TstNode(key, value, index)
} else {
this.value = value
}
}
/**
* @param {string} key
* @param {any} value
* @returns {void}
*/
add (key, value) {
const length = key.length
if (length === 0) {
throw new TypeError('Unreachable')
}View on GitHub (pinned to 1b2de5e052)
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.
Example fix
// before
const h = new Headers({ 'X-Custöm': 'val' })
// after
const h = new Headers({ 'X-Custom': 'val' }) Defensive patterns
Strategy: validation
Validate before calling
const HEADER_NAME_RE = /^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$/
function safeHeaderName(name) {
if (typeof name !== 'string' || !HEADER_NAME_RE.test(name)) {
throw new TypeError(`Invalid header name: ${String(name)}`)
}
return name
} Type guard
function isValidHeaderName(name) {
return typeof name === 'string' && /^[A-Za-z0-9!#$%&'*+\-.^_`|~]+$/.test(name)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- expected headers to be an array
- ${optionName} must be an array
- ${optionName} must contain header names
- expected opts.skipHeaderNames to be an array, got ${typeof s
- expected opts.excludeHeaderNames to be an array, got ${typeo
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/7b4220ec6ce75b57.
Report an issue: GitHub.