headroomlabs-ai/headroom · error · Error

proxyUrl must use http:// or https://

Error message

proxyUrl must use http:// or https://

What it means

The proxyUrl parsed successfully but its scheme is neither http: nor https: — Headroom routing only works over plain HTTP(S) proxies, so schemes like ws://, tcp:, or unix: are rejected upfront. This fires after parseProxyUrl succeeds but before path/query checks.

Source

Thrown at plugins/openclaw/src/proxy-manager.ts:417

      return null;
    }
  }
}

/** Parse a URL, returning the parsed object or throwing a descriptive error. */
function parseProxyUrl(proxyUrl: string): URL {
  try {
    return new URL(proxyUrl);
  } catch {
    throw new Error(`Invalid proxyUrl: "${proxyUrl}"`);
  }
}

export function normalizeAndValidateProxyUrl(proxyUrl: string): string {
  const parsed = parseProxyUrl(proxyUrl);

  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
    throw new Error("proxyUrl must use http:// or https://");
  }

  if (parsed.pathname !== "/" || parsed.search || parsed.hash) {
    throw new Error("proxyUrl must not include a path, query, or hash");
  }

  return parsed.origin;
}

/** Returns true if the URL points to a local address (localhost or 127.0.0.1). */
export function isLocalProxyUrl(proxyUrl: string): boolean {
  try {
    const parsed = new URL(proxyUrl);
    return parsed.hostname === "127.0.0.1" || parsed.hostname === "localhost";
  } catch {
    return false;
  }
}

View on GitHub (pinned to 322425c43b)

Solutions

  1. Use the proxy's HTTP(S) endpoint, e.g. "http://127.0.0.1:8787"
  2. If the deployment fronts Headroom with TLS, use https:// with the public origin
  3. Check the config template/env var that supplied the scheme (ws:// vs http:// mixups are the most common)

Example fix

// before
manager.configure({ proxyUrl: "ws://127.0.0.1:8787" }); // throws

// after
manager.configure({ proxyUrl: "http://127.0.0.1:8787" });
Defensive patterns

Strategy: type-guard

Validate before calling

function usesHttpScheme(value: string): boolean {
  try {
    return ["http:", "https:"].includes(new URL(value).protocol);
  } catch {
    return false;
  }
}

if (!usesHttpScheme(proxyUrl)) {
  throw new Error(`proxyUrl must use http:// or https:// (got ${proxyUrl})`);

Type guard

function isHttpProxyUrl(value: string): value is string {
  try {
    return new URL(value).protocol === "http:" || new URL(value).protocol === "https:";
  } catch {
    return false;
  }
}

Prevention

When it happens

Trigger: Passing proxyUrl values such as "ws://127.0.0.1:8787", "socks5://localhost:8787", "tcp://10.0.0.1:8787", or "file:///..." to normalizeAndValidateProxyUrl().

Common situations: Reusing a WebSocket endpoint URL from other Headroom/OpenClaw tooling as proxyUrl; confusion between the proxy's HTTP port and its WS/gRPC port; template variable that injects the wrong scheme.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/807caaddf03f3a1b. Report an issue: GitHub.