denoland/deno · error · NodeRangeError
ERR_HTTP2_INFO_STATUS_NOT_ALLOWED
ERR_HTTP2_INFO_STATUS_NOT_ALLOWED
Error message
Informational status codes cannot be used
What it means
The Http2ServerResponse.statusCode setter refuses 1xx codes (100-199) with ERR_HTTP2_INFO_STATUS_NOT_ALLOWED. Informational statuses in HTTP/2 are protocol-level events (100 Continue, 103 Early Hints) generated by the session stack; they cannot be set as the final response status the way they (mis)work in http1.
Source
Thrown at ext/node/polyfills/internal/http2/compat.js:609
return this[kStream].writableFinished;
}
get writableLength() {
return this[kStream].writableLength;
}
get writableObjectMode() {
return this[kStream].writableObjectMode;
}
get writableNeedDrain() {
return this[kStream].writableNeedDrain;
}
set statusCode(code) {
code |= 0;
if (code >= 100 && code < 200) {
throw new ERR_HTTP2_INFO_STATUS_NOT_ALLOWED();
}
if (code < 100 || code > 599) {
throw new ERR_HTTP2_STATUS_INVALID(code);
}
this[kState].statusCode = code;
}
setTrailer(name, value) {
validateString(name, "name");
name = StringPrototypeToLowerCase(StringPrototypeTrim(name));
assertValidHeader(name, value);
this[kTrailers][name] = value;
}
addTrailers(headers) {
const keys = ObjectKeys(headers);
let key = "";
for (let i = 0; i < keys.length; i++) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Only assign statusCode for final statuses (200-599); skip 1xx when forwarding
- For 103 Early Hints use response.writeEarlyHints() (Node >= 18.3) or skip the optimization
- Clamp when unsure: response.statusCode = status >= 200 ? status : 200
Example fix
// before
if (upstreamStatus) response.statusCode = upstreamStatus; // 103 throws
// after
if (upstreamStatus >= 200) response.statusCode = upstreamStatus;
else if (upstreamStatus === 103) response.writeEarlyHints({ link: preloadLink }); Defensive patterns
Strategy: validation
Validate before calling
function isFinalStatus(code) {
return Number.isInteger(code) && code >= 200 && code <= 599;
}
if (isFinalStatus(upstreamStatus)) res.statusCode = upstreamStatus;
else if (upstreamStatus === 103) res.writeEarlyHints({ link: preloadLink }); Type guard
function isSettableStatusCode(code: unknown): code is number {
return Number.isInteger(code) && code >= 200 && code <= 599;
} Try / catch
try {
res.statusCode = s;
} catch (err) {
if (err.code === "ERR_HTTP2_INFO_STATUS_NOT_ALLOWED") return; // drop 1xx silently
throw err;
} Prevention
- Never propagate 1xx from upstream into an outgoing final response
- Use writeEarlyHints() for 103; do not emulate it with statusCode
When it happens
Trigger: response.statusCode = 100/101/103; middleware copying a forwarded 1xx status from an upstream hop into the outgoing response; early-hints implementations trying to emit 103 by assigning statusCode.
Common situations: Proxy chains where an intermediate stored an informational status; code written for http1 that sets 100/101 manually; attempting 103 Early Hints without the dedicated API.
Related errors
- ERR_HTTP2_INVALID_INFO_STATUS
- ERR_HTTP2_STATUS_INVALID
- ERR_HTTP2_HEADERS_AFTER_RESPOND
- ERR_HTTP2_STATUS_101
- ERR_HTTP2_STATUS_INVALID
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/4449705d316bdd02.
Report an issue: GitHub.