musistudio/claude-code-router · error · Error
Only http and https URLs can be opened.
Error message
Only http and https URLs can be opened.
What it means
Thrown by normalizeExternalHttpUrl when asked to open a URL whose scheme is neither http: nor https:. The function parses the value with the URL constructor and whitelists only web schemes, deliberately blocking file:, javascript:, and other protocols.
Source
Thrown at packages/ui/src/web-client-bridge.ts:102
}
}
function noopSubscription(): () => void {
return () => undefined;
}
async function selectPluginDirectory(): Promise<unknown> {
const directory = window.prompt("Plugin directory path");
if (!directory?.trim()) {
return undefined;
}
return rpc("selectPluginDirectory", [directory.trim()]);
}
function normalizeExternalHttpUrl(value: string): string {
const url = new URL(value.trim());
if (url.protocol !== "http:" && url.protocol !== "https:") {
throw new Error("Only http and https URLs can be opened.");
}
return url.toString();
}
const webClientBridge: CcrApi = {
applyClaudeAppGateway: (config) => rpc("applyClaudeAppGateway", [config]) as ReturnType<CcrApi["applyClaudeAppGateway"]>,
applyProfile: () => rpc("applyProfile") as ReturnType<CcrApi["applyProfile"]>,
cancelBotGatewayQrLogin: (request) => rpc("cancelBotGatewayQrLogin", [request]) as ReturnType<CcrApi["cancelBotGatewayQrLogin"]>,
checkProviderConnectivity: (request) => rpc("checkProviderConnectivity", [request]) as ReturnType<CcrApi["checkProviderConnectivity"]>,
clearProxyNetworkCaptures: () => rpc("clearProxyNetworkCaptures") as ReturnType<CcrApi["clearProxyNetworkCaptures"]>,
closeBotGatewayQrWindow: (request) => rpc("closeBotGatewayQrWindow", [request]) as ReturnType<CcrApi["closeBotGatewayQrWindow"]>,
closeTray: () => Promise.resolve(),
detectProviderIcon: (request) => rpc("detectProviderIcon", [request]) as ReturnType<CcrApi["detectProviderIcon"]>,
exportData: () => rpc("exportData") as ReturnType<CcrApi["exportData"]>,
fetchProviderManifest: (request) => rpc("fetchProviderManifest", [request]) as ReturnType<CcrApi["fetchProviderManifest"]>,
getAgentAnalysis: (filter) => rpc("getAgentAnalysis", [filter]) as ReturnType<CcrApi["getAgentAnalysis"]>,
getAgentTracePayload: (request) => rpc("getAgentTracePayload", [request]) as ReturnType<CcrApi["getAgentTracePayload"]>,
getAppInfo: () => rpc("getAppInfo") as ReturnType<CcrApi["getAppInfo"]>,View on GitHub (pinned to 99f24806c6)
Solutions
- Use a full http(s) URL, e.g. https://example.com/page
- For local files, do not route them through this API — use the platform file-open mechanism instead
- Sanitize user input and reject non-http schemes before calling the bridge
Example fix
// before
openUrl("file:///home/user/report.html")
// after
openUrl("https://example.com/report.html") Defensive patterns
Strategy: type-guard
Validate before calling
try { const u = new URL(value); if (u.protocol !== "http:" && u.protocol !== "https:") throw new Error("blocked"); } catch { /* reject before calling bridge */ } Type guard
function isExternalHttpUrl(value: string): boolean {
try { const u = new URL(value.trim()); return u.protocol === "http:" || u.protocol === "https:"; }
catch { return false; }
} Try / catch
try { openExternal(url); } catch (e) { if (e instanceof Error && e.message === "Only http and https URLs can be opened.") return; throw e; } Prevention
- Whitelist http/https at the input boundary
- Open local files with shell.openPath, not the browser bridge
- Treat all user-supplied URLs as untrusted; validate scheme before use
When it happens
Trigger: Calling the open-URL bridge path with values like file:///home/user/doc.html, mailto:someone@example.com, about:blank, or a bare string that the URL constructor resolves to a non-http scheme.
Common situations: Passing local filesystem paths expecting them to open in a browser; user-supplied links from chat/config that use custom app schemes; Windows paths like C:\file.txt that parse as a drive-letter scheme.
Related errors
- Artifact URL contains an invalid access token.
- ${label} cannot include credentials.
- Only http, https, and CCR plugin URLs can be opened.
- Only http and https QR login URLs can be opened.
- ZCode profiles can only open the app; agent arguments are no
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/054de31c15da5549.
Report an issue: GitHub.