denoland/deno · warning
Setting the NODE_DEBUG environment variable to '${StringProt
Error message
Setting the NODE_DEBUG environment variable to '${StringPrototypeToLowerCase(set)}' can expose sensitive data (such as passwords, tokens and authentication headers) in the resulting log. What it means
node:util's debuglog initialization in Deno mirrors Node's warning for NODE_DEBUG=http/http2: enabling debug logging for the HTTP layers prints request/response internals, including URLs, headers, and potentially Authorization tokens (ext/node/polyfills/internal/util/debuglog.ts:57-66). It is a privacy/security heads-up, not a functional problem; the debug logging still happens if you keep the variable set.
Source
Thrown at ext/node/polyfills/internal/util/debuglog.ts:64
"*",
".*",
),
",",
"$|^",
);
const debugEnvRegex = new SafeRegExp(`^${debugEnv}$`, "i");
testEnabled = (str) => RegExpPrototypeExec(debugEnvRegex, str) !== null;
} else {
testEnabled = () => false;
}
}
// Emits warning when user sets
// NODE_DEBUG=http or NODE_DEBUG=http2.
function emitWarningIfNeeded(set: string) {
if ("HTTP" === set || "HTTP2" === set) {
// deno-lint-ignore no-console
console.warn(
"Setting the NODE_DEBUG environment variable " +
"to '" + StringPrototypeToLowerCase(set) + "' can expose sensitive " +
"data (such as passwords, tokens and authentication headers) " +
"in the resulting log.",
);
}
}
const noop = () => {};
function debuglogImpl(
enabled: boolean,
set: string,
): (...args: unknown[]) => void {
if (debugImpls[set] === undefined) {
if (enabled) {
emitWarningIfNeeded(set);
debugImpls[set] = function debug(msg, ...args: unknown[]) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Remove http and http2 from NODE_DEBUG and keep only what you need (e.g., NODE_DEBUG=net,stream)
- Scope NODE_DEBUG to a single debug invocation (NODE_DEBUG=http deno run app.js) instead of exporting it globally
- If HTTP tracing is genuinely required, redact Authorization/Cookie/set-cookie headers from logs before they are stored or shared
- Audit CI containers and env files for stale NODE_DEBUG values
Example fix
# before export NODE_DEBUG=http,http2,net deno run app.js # warning: http/http2 debug can leak credentials # after NODE_DEBUG=net,stream deno run app.js # non-header-dumping sections only
Defensive patterns
Strategy: validation
Validate before calling
// scrub http/http2 from NODE_DEBUG before node modules initialize debuglog
const parts = (Deno.env.get("NODE_DEBUG") ?? "")
.split(",")
.map((s) => s.trim())
.filter((s) => s && s.toLowerCase() !== "http" && s.toLowerCase() !== "http2");
if (parts.length) Deno.env.set("NODE_DEBUG", parts.join(","));
else Deno.env.delete("NODE_DEBUG"); Prevention
- Never export NODE_DEBUG=http in shells, Dockerfiles, or CI defaults; scope it to one command
- Redact Authorization/Cookie/set-cookie headers from any pipeline that captures debug output
- Audit CI secrets and env files for stale NODE_DEBUG values periodically
When it happens
Trigger: The NODE_DEBUG environment variable contains http or http2 (matching is case-insensitive, including inside comma-separated lists like NODE_DEBUG=http,net), and node code initializes debuglog for those sections. The check is exact section matching: 'HTTP' === set || 'HTTP2' === set after uppercase normalization.
Common situations: NODE_DEBUG=http exported in .bashrc/.zshrc, Dockerfiles, or CI defaults to debug fetch/undici-style issues and never removed; CI logs captured and shared with embedded Authorization/Cookie headers; pairing NODE_DEBUG with token-authenticated internal services.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- ERR_INVALID_HTTP_TOKEN
- Invalid header value: "${value}"
- ERR_INVALID_HTTP_TOKEN
- ERR_HTTP_HEADERS_SENT
- ERR_INVALID_CHAR
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/a12d553cd13252a6.
Report an issue: GitHub.