denoland/deno · error · Error
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 - used by setGlobalProxyFromEnv(envObject) and new http.Agent({ proxyEnv }) - parseProxyUrl requires proxy values to be strings. A present, non-empty, non-string value (number, boolean, object) throws ERR_PROXY_INVALID_CONFIG with 'Invalid proxy URL for <kind>: must be a string', naming which variable (http_proxy/https_proxy) is at fault.
Solutions
- Provide full URL strings: { http_proxy: 'http://proxy.local:8080' }.
- Stringify when building the object programmatically: proxyEnv: { http_proxy: String(cfg.proxyUrl) }.
- Omit the key entirely (or empty string) when no proxy should be configured.
Example fix
// before
setGlobalProxyFromEnv({ http_proxy: 8080 }); // number -> ERR_PROXY_INVALID_CONFIG
// after
setGlobalProxyFromEnv({ http_proxy: 'http://127.0.0.1:8080' }); Defensive patterns
Strategy: validation
Validate before calling
function normalizeProxyEnv(cfg) {
const out = {};
for (const k of ['http_proxy', 'https_proxy']) {
const v = cfg[k];
if (v === undefined || v === null || v === '') continue;
out[k] = String(v); // reject non-strings before the library does
if (typeof v !== 'string') throw new Error(`${k} must be a string`);
}
return out;
}
setGlobalProxyFromEnv(normalizeProxyEnv(config)); Type guard
function isProxyEnvObject(o) {
return o !== null && typeof o === 'object' && !Array.isArray(o) &&
Object.values(o).every((v) => v === undefined || v === '' || typeof v === 'string');
} Try / catch
try {
const restore = setGlobalProxyFromEnv(env);
} catch (err) {
if (err.code === 'ERR_PROXY_INVALID_CONFIG') {
// message names the offending variable: log it, fix config, keep previous proxy via restore semantics
} else throw err;
} Prevention
- Always pass full URL strings ('http://host:port') in proxyEnv objects.
- Stringify config-sourced values when assembling the object.
- Validate the shape once at config load; fail fast with the key name.
When it happens
Trigger: setGlobalProxyFromEnv({ http_proxy: 8080 }); new http.Agent({ proxyEnv: { https_proxy: true } }); JSON config deserialized into the env object with numeric ports or booleans instead of full URL strings.
Common situations: Config files storing the proxy as host:port pieces or numbers and assembling the object without stringification; feature flags (true/false) accidentally placed in the proxyEnv slot; environment snapshots from tools that preserve original JS types.
Related errors
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/4be7d864d0ab09dc.
Report an issue: GitHub.
Appendix: 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 9ad36f7a2c)