http.validateHeaderName()
Throws if the given string is not a valid HTTP header name, otherwise returns undefined.
http.validateHeaderName(name[, label])- Added in Node.js v14.3.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$name | string | The candidate header name. Must be a non-empty RFC 9110 token: letters, digits, and the characters ! # $ % & ' * + - . ^ _ ` | ~ only. |
$labeloptional | string= 'Header name' | Label used at the start of the error message, so the throw can name what was being validated. |
Return value
undefinedNothing. The function communicates only by throwing — a normal return means the name is valid.
Errors
Throws a TypeError with code 'ERR_INVALID_HTTP_TOKEN' when name is empty or contains any character outside the HTTP token set.
Changelog
- PHP v19.5.0, v18.14.0The label parameter was added; before this, the message always began with 'Header name'.
http.validateHeaderName() runs exactly the check that response.setHeader(name, value) performs, without setting anything. It is pure string validation: no socket, no server, no request.
When to reach for it
You do not need it for ordinary code — the HTTP module validates every header you set anyway. It earns its place when a header name comes from outside your program: a config file, a CLI flag, a database row, a proxy rule mapping upstream fields to downstream ones. Validating at the boundary lets you reject the bad value where you can report the offending config key, rather than mid-request where the throw takes down a response.
What trips people up
- Valid means well-formed, not sensible.
x_customand!!!both pass; the token grammar allows underscores and punctuation. It says nothing about whether a proxy will forward the header — nginx drops underscored names by default. - Returning
undefinedis success. Writingif (validateHeaderName(n))is always false; use try/catch. - Empty string throws, which is the common case when an optional config value is missing.
- Names only. Values have their own grammar — pair this with
http.validateHeaderValue(name, value).
Example
When to use it
- Validate header names loaded from a YAML or JSON config at startup instead of at request time
- Sanitise a proxy's header-rewrite rules before the process begins serving traffic
- Reject user-supplied header names in an admin UI with a message pointing at the bad field
- Assert in a test that a header-building helper never produces an illegal name
Frequently asked questions
What does ERR_INVALID_HTTP_TOKEN mean?
A header name contained a character outside the HTTP token set, or was empty. Legal characters are letters, digits, and ! # $ % & ' * + - . ^ _ ` | ~ — spaces, colons, and non-ASCII characters all trigger it. The message includes the offending value in brackets.
Do I need to call validateHeaderName() before setting a header?
No. The HTTP module validates every header name you pass to setHeader(), writeHead(), or a request's headers option. Call it explicitly only when the name comes from outside your code — config, user input, a proxy rule — and you want to fail at that boundary rather than mid-request.
How do I check that a header name is valid in Node?
Wrap http.validateHeaderName(name) in try/catch: no throw means valid. It returns undefined on success, so a truthiness check like if (validateHeaderName(name)) is always false and will silently mark every valid name as invalid.
More examples
Validating configured headers at startup
Both problems are reported at boot with the offending key named, instead of one of them crashing a request handler weeks later. Pairing the two validators is the point: the name check and the value check have different grammars and different error codes, and a config file can violate either.
const http = require('node:http');
const config = {
'X-Powered-By': 'acme',
'X-Env': 'prod',
'X Trace': 'on', // space -- invalid name
'X-Empty': undefined, // invalid value
};
function validateHeaders(obj) {
const problems = [];
for (const [name, value] of Object.entries(obj)) {
try {
http.validateHeaderName(name, 'Configured header name');
http.validateHeaderValue(name, value);
} catch (err) {
problems.push(`${err.code}: ${err.message}`);
}
}
return problems;
}
const problems = validateHeaders(config);
if (problems.length) {
for (const p of problems.sort()) console.error(p);
process.exit(1);
}
// ERR_HTTP_INVALID_HEADER_VALUE: Invalid value "undefined" for header "X-Empty"
// ERR_INVALID_HTTP_TOKEN: Configured header name must be a valid HTTP token ["X Trace"]Filtering headers a reverse proxy is asked to forward
A proxy copies headers it did not author, so a malformed one would otherwise throw inside http.request() and abort a request that was already half-answered. Validating first turns that into a silent drop. The hop-by-hop set is removed separately — those names are perfectly valid tokens, so the validator will not catch them.
const http = require('node:http');
const HOP_BY_HOP = new Set([
'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization',
'te', 'trailer', 'transfer-encoding', 'upgrade',
]);
function forwardableHeaders(incoming) {
const out = {};
for (const [name, value] of Object.entries(incoming)) {
if (HOP_BY_HOP.has(name.toLowerCase())) continue;
try {
http.validateHeaderName(name, 'Upstream header name');
http.validateHeaderValue(name, value);
} catch {
continue; // drop anything malformed rather than throwing mid-request
}
out[name] = value;
}
return out;
}
const server = http.createServer((req, res) => {
const headers = forwardableHeaders(req.headers);
const upstream = http.request('http://backend.internal' + req.url, {
method: req.method,
headers,
}, (upRes) => {
res.writeHead(upRes.statusCode, upRes.headers);
upRes.pipe(res);
});
upstream.on('error', () => res.writeHead(502).end());
req.pipe(upstream);
});
server.listen(3000);
Discussion