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

  1. Provide full URL strings: { http_proxy: 'http://proxy.local:8080' }.
  2. Stringify when building the object programmatically: proxyEnv: { http_proxy: String(cfg.proxyUrl) }.
  3. 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

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)