aaif-goose/goose · error

External ACP backend URL must use http: or https:, got ${url

Error message

External ACP backend URL must use http: or https:, got ${url.protocol}

What it means

Thrown by normalizeAcpHttpBaseUrl when the input parses as a URL but its protocol is neither http: nor https:. Because the endpoint is used to build WebSocket/HTTP ACP endpoints, the code requires a plain web scheme and rejects anything else — most commonly ws:// or wss:// pasted by users who copied the WebSocket URL, or file:///ftp:// typos.

Source

Thrown at ui/desktop/src/acp/url.ts:46

function isIpv4LoopbackLiteral(hostname: string): boolean {
  const octets = hostname.split('.');
  if (octets.length !== 4 || octets.some((octet) => !/^\d+$/.test(octet))) {
    return false;
  }

  return octets.every((octet) => Number(octet) <= 255) && Number(octets[0]) === 127;
}

export function normalizeAcpHttpBaseUrl(rawBaseUrl: string): string {
  const trimmed = rawBaseUrl.trim();
  if (!trimmed) {
    throw new Error('External ACP backend URL is required');
  }

  const url = new URL(trimmed);
  if (url.protocol !== 'http:' && url.protocol !== 'https:') {
    throw new Error(`External ACP backend URL must use http: or https:, got ${url.protocol}`);
  }

  if (url.search || url.hash) {
    throw new Error('External ACP backend URL must not include query parameters or fragments');
  }

  const pathname = url.pathname.replace(/\/+$/, '');
  if (pathname.endsWith('/acp')) {
    throw new Error('External ACP backend URL must be the base URL before /acp');
  }

  return `${url.origin}${pathname}`;
}

function httpEndpointUrlFromHttpBase(rawBaseUrl: string, endpoint: 'status' | 'acp'): string {
  const baseUrl = normalizeAcpHttpBaseUrl(rawBaseUrl);
  const url = new URL(baseUrl);
  url.pathname = `${url.pathname.replace(/\/+$/, '')}/${endpoint}`;

View on GitHub (pinned to 3810898a74)

Solutions

  1. Use the http(s) base URL of the backend (e.g. http://127.0.0.1:8080) — the code appends /acp itself.
  2. If the value starts with ws:// or wss://, convert the scheme to http:// or https:// and keep host/port.
  3. Always include the scheme; host:port alone makes new URL throw a different error.

Example fix

// before
const url = new URL(trimmed);
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
  throw new Error(`External ACP backend URL must use http: or https:, got ${url.protocol}`);
}

// after (auto-correct the common ws paste, then validate)
const corrected = trimmed.replace(/^wss?:\/\//i, (m) => (m.toLowerCase() === 'ws://' ? 'http://' : 'https://'));
const url = new URL(corrected);
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
  throw new Error(`External ACP backend URL must use http: or https:, got ${url.protocol}`);
}
Defensive patterns

Strategy: validation

Validate before calling

// Normalize the common ws:// paste, then check the scheme
function toHttpBaseUrl(raw: string): string {
  const value = raw.trim().replace(/^ws:\/\//i, 'http://').replace(/^wss:\/\//i, 'https://');
  const { protocol } = new URL(value);
  if (protocol !== 'https:' && protocol !== 'http:') {
    throw new Error(`Unsupported scheme ${protocol}; use http:// or https://`);
  }
  return value;
}

Type guard

function isHttpUrl(value: string): boolean {
  try {
    const { protocol } = new URL(value.trim());
    return protocol === 'http:' || protocol === 'https:';
  } catch {
    return false;
  }
}

Try / catch

try {
  const base = normalizeAcpHttpBaseUrl(inputUrl);
} catch (error) {
  if (/must use http: or https:/.test(String(error))) {
    setFieldError('backendUrl', 'Use http:// or https:// — the /acp websocket path is added automatically');
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: normalizeAcpHttpBaseUrl('ws://127.0.0.1:8080/acp') — user copied the ws URL from logs; 'unix:///path' or 'file://...' entries; a URL missing the scheme entirely can also fail URL parsing (that throws a TypeError from new URL, not this message).

Common situations: Copy-pasting the ws:// URL that getAcpUrl returns elsewhere in the app; docs or tutorials showing the WebSocket endpoint; automation writing scheme-less host:port values.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/aa5f7edc7e962dc0. Report an issue: GitHub.