farion1231/cc-switch · warning · Error

Invalid URL

Error message

Invalid URL

What it means

Thrown by settings.openExternal(url) when new URL(url) fails (the value is not a parseable absolute URL) - and, because the scheme-check throw shares the same catch, it is also the message surfaced for any non-http/https scheme. It is the single error callers see for malformed or disallowed input to the external-open API.

Source

Thrown at src/lib/api/settings.ts:223

  async syncCurrentProvidersLive(): Promise<void> {
    const result = (await invoke("sync_current_providers_live")) as {
      success?: boolean;
      message?: string;
    };
    if (!result?.success) {
      throw new Error(result?.message || "Sync current providers failed");
    }
  },

  async openExternal(url: string): Promise<void> {
    try {
      const u = new URL(url);
      const scheme = u.protocol.replace(":", "").toLowerCase();
      if (scheme !== "http" && scheme !== "https") {
        throw new Error("Unsupported URL scheme");
      }
    } catch {
      throw new Error("Invalid URL");
    }
    await invoke("open_external", { url });
  },

  async setAutoLaunch(enabled: boolean): Promise<boolean> {
    return await invoke("set_auto_launch", { enabled });
  },

  async getAutoLaunchStatus(): Promise<boolean> {
    return await invoke("get_auto_launch_status");
  },

  async getToolVersions(
    tools?: string[],
    wslShellByTool?: Record<
      string,
      { wslShell?: string | null; wslShellFlag?: string | null }
    >,

View on GitHub (pinned to a2e22f3302)

Solutions

  1. Normalize input to a full URL first: url.startsWith('http') ? url : `https://${url}`
  2. Validate with new URL() plus a protocol check in the UI layer before invoking
  3. Treat an empty string as a no-op click instead of calling the API

Example fix

// before
await settingsApi.openExternal(href); // 'example.com/docs' -> Invalid URL

// after
const normalized = /^https?:\/\//.test(href) ? href : `https://${href}`;
await settingsApi.openExternal(normalized);
Defensive patterns

Strategy: validation

Validate before calling

function normalizeExternalUrl(href: string): string | null {
  if (!href.trim()) return null;
  const candidate = /^https?:\/\//i.test(href) ? href : `https://${href}`;
  try {
    const { protocol } = new URL(candidate);
    return protocol === "http:" || protocol === "https:" ? candidate : null;
  } catch {
    return null;
  }
}

const url = normalizeExternalUrl(href);
if (url) await settingsApi.openExternal(url);

Try / catch

try {
  await settingsApi.openExternal(url);
} catch (e) {
  if (e instanceof Error && e.message === "Invalid URL") {
    log.warn("Rejected external URL", { url });
    toast("This link is not a valid http(s) URL");
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: openExternal('example.com/path') (no scheme, new URL throws), openExternal(''), openExternal('http://'), plus ftp://x and other non-http schemes via the rewritten catch.

Common situations: Config fields storing bare domains without a scheme; template strings producing empty hrefs; the 'Unsupported URL scheme' case masquerading as this message.

Related errors


AI-assisted analysis of farion1231/cc-switch@a2e22f3302 (2026-08-16). Data as JSON: /api/errors/f041c76e9baa8887. Report an issue: GitHub.