CloakHQ/CloakBrowser · warning

[cloakbrowser] Malformed HTTP proxy URL, passing through…

Error message

[cloakbrowser] Malformed HTTP proxy URL, passing through unchanged: invalid port

What it means

The HTTP/HTTPS proxy URL normalizer detected a non-numeric port in the authority and cannot safely rewrite the URL. It logs this warning and returns the (partially normalized) URL unchanged instead of corrupting it.

Solutions

  1. Correct the URL to a numeric port: http://host:8080.
  2. Bracket IPv6 hosts: http://[::1]:8080.
  3. Trim whitespace and remove path/query suffixes from the proxy value; check how the env var or config was assembled.
  4. Test the URL with new URL(proxy) before passing it to catch structural mistakes early.

Example fix

// before
const proxy = 'http://proxy.example.com:80x/';

// after
const proxy = 'http://proxy.example.com:8080';
Defensive patterns

Strategy: validation

Validate before calling

function isValidHttpProxy(u: string): boolean {
  try {
    const p = new URL(u);
    if (!/^https?:$/.test(p.protocol)) return false;
    return p.port === '' || /^\d+$/.test(p.port);
  } catch { return false; }
}
if (!isValidHttpProxy(proxy)) throw new Error(`bad HTTP proxy URL: ${proxy}`);

Type guard

const isWellFormedHttpProxy = (u: string): boolean =>
  /^https?:\/\/\S+@?(\[[^\]]+\]|[^:\s\/]+):\d+\/?$/.test(u.trim());

Prevention

When it happens

Trigger: Passing proxy: 'http://host:8080abc' or 'http://host:port/path' where the segment after the last colon (respecting IPv6 brackets) fails /^\d+$/, via resolveProxyConfig or resolveProxy.

Common situations: Env-var proxies (HTTP_PROXY) with typos, URLs pasted with trailing slashes in the wrong place, string concatenation bugs appending text after the port, IPv6 hosts without brackets.

Understand the failure class

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/20033ca9153d38d4. Report an issue: GitHub.

Appendix: source

Thrown at js/src/proxy.ts:197

 */
export function normalizeHttpStringUrl(urlStr: string): string {
  const normalized = urlStr.includes("://") ? urlStr : `http://${urlStr}`;
  const schemeMatch = normalized.match(/^([a-z][a-z0-9+\-.]*):\/\/(.*)$/i);
  if (!schemeMatch) return normalized;
  const [, scheme, rest] = schemeMatch;
  const hostStart = rest.search(/[/?#]/);
  const authority = hostStart === -1 ? rest : rest.slice(0, hostStart);
  const suffix = hostStart === -1 ? "" : rest.slice(hostStart);
  const atIdx = authority.lastIndexOf("@");
  if (atIdx === -1) return normalized;
  const userinfo = authority.slice(0, atIdx);
  const hostPart = authority.slice(atIdx + 1);
  const bracketEnd = hostPart.lastIndexOf("]");
  const portColonIdx = hostPart.indexOf(":", Math.max(bracketEnd, 0));
  if (portColonIdx !== -1) {
    const portStr = hostPart.slice(portColonIdx + 1);
    if (portStr && !/^\d+$/.test(portStr)) {
      console.warn(`[cloakbrowser] Malformed HTTP proxy URL, passing through unchanged: invalid port`);
      return normalized;
    }
  }
  const hostAndRest = hostPart + suffix;
  const colonIdx = userinfo.indexOf(":");
  const rawUserEnc = colonIdx === -1 ? userinfo : userinfo.slice(0, colonIdx);
  const hasPassword = colonIdx !== -1;
  const rawPassEnc = hasPassword ? userinfo.slice(colonIdx + 1) : "";
  try {
    const encUser = rawUserEnc ? encodeURIComponent(lenientDecodeURIComponent(rawUserEnc)) : "";
    const encPass = hasPassword
      ? (rawPassEnc ? encodeURIComponent(lenientDecodeURIComponent(rawPassEnc)) : "")
      : null;
    let userinfoPart: string;
    if (encPass !== null) {
      userinfoPart = `${encUser}:${encPass}@`;
    } else if (encUser) {
      userinfoPart = `${encUser}@`;

View on GitHub (pinned to d6bad5de26)