denoland/deno · error · NodeError
ERR_PROXY_INVALID_CONFIG
ERR_PROXY_INVALID_CONFIG
Error message
Invalid proxy URL for ${kind}: must be a string What it means
In strict mode (an explicit proxyEnv object passed to http.setGlobalProxyFromEnv(env) or new http.Agent({ proxyEnv })), parseProxyUrl throws ERR_PROXY_INVALID_CONFIG 'must be a string' when the value for http_proxy/https_proxy/HTTPS_PROXY-style keys is present but not a string (number, boolean, object).
Source
Thrown at ext/node/polyfills/_http_proxy.js:110
function readEnvKey(env, keys) {
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
if (env[k] !== undefined && env[k] !== "") {
return env[k];
}
}
return undefined;
}
const CRLF_RE = new SafeRegExp(/[\r\n]/);
function parseProxyUrl(raw, kind, mode) {
if (raw === undefined || raw === null || raw === "") return null;
if (typeof raw !== "string") {
if (mode === "env") {
throw new TypeError(`Invalid URL: ${raw}`);
}
throw new ERR_PROXY_INVALID_CONFIG(
`Invalid proxy URL for ${kind}: must be a string`,
);
}
// CRLF injection guard - check raw string before URL parsing strips them.
// Matches Node's CRLF rejection in the proxy URL validator. We surface this
// even for env-derived URLs so the auth tests get the expected error class.
if (RegExpPrototypeExec(CRLF_RE, raw) !== null) {
throw new ERR_PROXY_INVALID_CONFIG(`Invalid proxy URL: ${raw}`);
}
let url;
try {
url = new URL(raw);
} catch {
if (mode === "env") {
throw new TypeError(`Invalid URL: ${raw}`);
}
throw new ERR_PROXY_INVALID_CONFIG(`Invalid proxy URL: ${raw}`);
}View on GitHub (pinned to 89f33cbef2)
Solutions
- Pass URL strings in proxyEnv objects: { https_proxy: 'http://proxy:8080' }
- Validate your config object before handing it to the API (see validation below)
- Omit the key entirely (or leave it undefined) when no proxy should be configured
Example fix
// before
http.setGlobalProxyFromEnv({ http_proxy: config.port }); // number -> throws
// after
http.setGlobalProxyFromEnv({ http_proxy: `http://${config.host}:${config.port}` }); Defensive patterns
Strategy: type-guard
Validate before calling
function normalizeProxyEnv(env: Record<string, unknown>) {
const out: Record<string, string> = {};
for (const [k, v] of Object.entries(env)) {
if (v === undefined || v === null || v === '') continue;
out[k] = String(v); // coerce numbers/booleans to strings
}
return out;
} Type guard
function isStringProxyEnv(env: unknown): env is Record<string, string> {
return !!env && typeof env === 'object' && !Array.isArray(env) &&
Object.values(env).every((v) => v === undefined || typeof v === 'string');
} Try / catch
try {
http.setGlobalProxyFromEnv(proxyEnv);
} catch (e) {
if (e?.code === 'ERR_PROXY_INVALID_CONFIG' && /must be a string/.test(e.message)) {
http.setGlobalProxyFromEnv(normalizeProxyEnv(proxyEnv)); // retry coerced
} else throw e;
} Prevention
- Quote proxy URLs in JSON/YAML config so they stay strings
- Validate proxyEnv shape at config load time
- Remember empty string/undefined/null keys mean 'unset', not error
When it happens
Trigger: setGlobalProxyFromEnv({ http_proxy: 123 }) or new Agent({ proxyEnv: { https_proxy: true } }); note undefined/null/'' are treated as unset and return null instead of throwing.
Common situations: Proxy config parsed from JSON/YAML where the port or whole URL ended up as a number/boolean; config templating that interpolates values without quoting.
Related errors
- ERR_INVALID_ARG_TYPE
- Unexpected 'name' field in options, bench name is already pr
- ${prefix}Linter plugin name must only contain lowercase lett
- The url passed into 'proxy.url' has an invalid scheme for th
- Invalid value for 'proxy.transport' option: ${JSONStringify(
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/4be7d864d0ab09dc.
Report an issue: GitHub.