farion1231/cc-switch · error · Error
Invalid URL
Error message
Invalid URL
What it means
settingsApi.openExternal validates the URL before handing it to the Tauri open_external command: it must parse with new URL and its scheme must be http or https. Because both the parse failure and the scheme mismatch land in the same catch, the specific 'Unsupported URL scheme' message is swallowed and every rejection surfaces as the generic 'Invalid URL'.
Solutions
- Pass fully-qualified http:// or https:// URLs to openExternal
- Normalize stored URLs to include a scheme when saving settings
- If distinct messaging is needed, move the scheme check outside the try so 'Unsupported URL scheme' survives (see exampleFix)
Example fix
// before
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'); // also swallows the scheme message
}
// after
let u: URL;
try {
u = new URL(url);
} catch {
throw new Error('Invalid URL');
}
const scheme = u.protocol.replace(':', '').toLowerCase();
if (scheme !== 'http' && scheme !== 'https') {
throw new Error('Unsupported URL scheme');
} Defensive patterns
Strategy: validation
Validate before calling
function isOpenableExternalUrl(url: string): boolean {
try {
const u = new URL(url);
const scheme = u.protocol.replace(':', '').toLowerCase();
return scheme === 'http' || scheme === 'https';
} catch {
return false;
}
}
if (!isOpenableExternalUrl(link)) {
// show a friendly message instead of calling openExternal
} Try / catch
try {
await settingsApi.openExternal(url);
} catch (error) {
if (error instanceof Error && error.message === 'Invalid URL') {
// hint: links must be absolute http(s)
} else {
throw error;
}
} Prevention
- Store URLs with an explicit scheme at save time
- Never feed user-typed strings straight to openExternal
- If you need scheme-specific messages, keep the scheme check outside the parse try-block
When it happens
Trigger: Calling openExternal('ftp://example.com/f'), openExternal('file:///etc/hosts'), openExternal('example.com') (no scheme, so the URL constructor throws), or any unparseable string.
Common situations: Clicking a help/update link stored without a scheme; user-supplied docs or webhook URLs; trying to open mailto: or custom deep links that this guard forbids.
Related errors
- ${error}
- DOWNLOAD_TIMEOUT
- error while running tauri application
- INVALID_SKILL_DIRECTORY
- } must be an absolute HTTP or HTTPS URL
AI-assisted analysis of farion1231/cc-switch@0b5da51016 (2026-08-20).
Data as JSON: /api/errors/f041c76e9baa8887.
Report an issue: GitHub.
Appendix: 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 0b5da51016)