denoland/deno · error · NodeTypeError
ERR_INVALID_ARG_TYPE
ERR_INVALID_ARG_TYPE
Error message
The "statusCode" argument must be of type integer [100, 999]. Received ${statusCode} What it means
writeHead coerces statusCode with statusCode |= 0 and then requires the range 100..999. Values outside it throw ERR_INVALID_ARG_TYPE asking for 'integer [100, 999]' (Node's quirk: an out-of-range status uses the arg-type error code). NaN|0 and undefined|0 both become 0, so missing or unparseable statuses fail here too.
Source
Thrown at ext/node/polyfills/_http_server.js:509
this._writeRaw(head, "ascii", cb);
};
ServerResponse.prototype._implicitHeader = function _implicitHeader() {
this.writeHead(this.statusCode);
};
ServerResponse.prototype.writeHead = function writeHead(
statusCode,
reason,
obj,
) {
if (this._header) {
throw new ERR_HTTP_HEADERS_SENT("write");
}
statusCode |= 0;
if (statusCode < 100 || statusCode > 999) {
throw new ERR_INVALID_ARG_TYPE(
"statusCode",
"integer [100, 999]",
statusCode,
);
}
if (typeof reason === "string") {
this.statusMessage = reason;
} else {
this.statusMessage ||= STATUS_CODES[statusCode] || "unknown";
obj ??= reason;
}
this.statusCode = statusCode;
// Enforce no body for 204 and 304 responses
if (statusCode === 204 || statusCode === 304) {
this._hasBody = false;
}View on GitHub (pinned to 89f33cbef2)
Solutions
- Validate the status is an integer in [100, 999] before calling writeHead, defaulting to 200 otherwise
- Fix the producer of the bad value (config parsing, Number() on user input)
- Never forward raw Number(userInput) results into the status
- Whitelist allowed statuses per endpoint
Example fix
// before const code = Number(req.query.status); // NaN or out of range res.writeHead(code); // after const parsed = Number(req.query.status); const code = Number.isInteger(parsed) && parsed >= 100 && parsed <= 999 ? parsed : 200; res.writeHead(code);
Defensive patterns
Strategy: validation
Validate before calling
function validStatusCode(code) {
return Number.isInteger(code) && code >= 100 && code <= 999;
}
const status = validStatusCode(raw) ? raw : 200;
res.writeHead(status); Type guard
function isStatusCode(v) {
return typeof v === 'number' && Number.isInteger(v) && v >= 100 && v <= 999;
} Try / catch
try {
res.writeHead(code);
} catch (e) {
if (e.code === 'ERR_INVALID_ARG_TYPE' && /statusCode/.test(e.message)) {
res.writeHead(200);
} else throw e;
} Prevention
- Never forward raw Number(userInput) into writeHead
- Keep a per-endpoint whitelist of allowed statuses
- Unit-test handlers with edge statuses 99, 100, 999, 1000 and NaN
When it happens
Trigger: res.writeHead(99), res.writeHead(1000), res.writeHead(NaN), res.writeHead(undefined), or res.writeHead('abc') (coerces to 0); a status computed from config, headers, or query params without validation.
Common situations: Status read from a config file or proxied header (Number(req.headers['x-status']) producing NaN); typos like 2000; a missing value defaulting to 0 instead of 200; arithmetic on optional fields yielding NaN.
Related errors
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_URL
- ERR_UNESCAPED_CHARACTERS
- ERR_INVALID_HTTP_TOKEN
- ERR_INVALID_HTTP_TOKEN
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/03056f6bb3f4c264.
Report an issue: GitHub.