aaif-goose/goose · error

External ACP backend URL must not include query parameters o

Error message

External ACP backend URL must not include query parameters or fragments

What it means

Thrown by normalizeAcpHttpBaseUrl when the parsed URL contains a query string (url.search) and/or a fragment (url.hash). The base URL is used verbatim to construct .../status and .../acp endpoints, so any ?params or #fragment would either corrupt those paths or be silently dropped; the function rejects them up front.

Source

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

    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}`;
  return url.toString();
}

export function statusHttpUrlFromHttpBase(rawBaseUrl: string): string {

View on GitHub (pinned to 3810898a74)

Solutions

  1. Strip everything after the path: keep only scheme://host[:port]/path.
  2. Pass tokens/credentials through the mechanism the backend actually supports, not URL query params.
  3. If callers may paste decorated URLs, strip search and hash before calling normalizeAcpHttpBaseUrl.

Example fix

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

// after (caller sanitizes the pasted URL first)
const raw = new URL(userInput);
raw.search = '';
raw.hash = '';
const baseUrl = normalizeAcpHttpBaseUrl(raw.toString());
Defensive patterns

Strategy: validation

Validate before calling

// Strip query/fragment before validation
function cleanBaseUrl(raw: string): string {
  const url = new URL(raw.trim());
  url.search = '';
  url.hash = '';
  return url.toString();
}

Type guard

function isBareHttpUrl(value: string): boolean {
  try {
    const url = new URL(value.trim());
    return (url.protocol === 'http:' || url.protocol === 'https:') && !url.search && !url.hash;
  } catch {
    return false;
  }
}

Try / catch

try {
  const base = normalizeAcpHttpBaseUrl(inputUrl);
} catch (error) {
  if (/query parameters or fragments/.test(String(error))) {
    return normalizeAcpHttpBaseUrl(cleanBaseUrl(inputUrl)); // retry with sanitized input
  }
  throw error;
}

Prevention

When it happens

Trigger: Passing 'http://host:8080/?token=abc' or 'https://host/goose#section'; URLs copied from a browser address bar after navigating (fragments get appended); config values containing a token query parameter because the user tried to inline auth.

Common situations: Trying to embed an auth token in the URL (tokens belong elsewhere); pasting a URL with utm params or anchors; bookmarks adding fragments.

Related errors


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