musistudio/claude-code-router · error · Error
Unsupported link protocol.
Error message
Unsupported link protocol.
What it means
Thrown when the parsed deep link's protocol is not the app deep-link protocol (appDeepLinkProtocol, i.e. ccr:). parseProviderManifestDeepLinkPayload only accepts its own scheme; anything else (https:, ccr-dev:, typo'd scheme) is rejected before host validation.
Source
Thrown at packages/core/src/contracts/deep-link.ts:78
} catch (error) {
return {
error: error instanceof Error ? error.message : String(error),
id,
rawUrl,
receivedAt: receivedAt.toISOString()
};
}
}
export function parseProviderManifestDeepLinkPayload(rawUrl: string): ProviderManifestDeepLinkPayload | undefined {
const value = rawUrl.trim();
if (value.length > maxDeepLinkLength) {
throw new Error("Provider link is too long.");
}
const url = new URL(value);
if (url.protocol !== `${appDeepLinkProtocol}:`) {
throw new Error("Unsupported link protocol.");
}
const host = url.hostname.toLowerCase();
const firstPathSegment = url.pathname.split("/").filter(Boolean)[0]?.toLowerCase();
if (host !== providerDeepLinkHost && firstPathSegment !== providerDeepLinkHost) {
throw new Error("Unsupported CCR link target.");
}
const payload = readPayloadRecord(url.searchParams);
const manifestUrl = boundedString(
firstStringParam(url.searchParams, ["manifest"]) ??
firstPayloadString(payload, ["manifest"]),
maxManifestUrlLength,
"Manifest URL"
);
if (!manifestUrl) {
return undefined;
}View on GitHub (pinned to 99f24806c6)
Solutions
- Ensure the link starts with ccr:// (the current appDeepLinkProtocol)
- If generating links, build them with the same constant the parser uses rather than hardcoding
- Check for transport mangling (encoded %3A instead of ':') and decode before parsing
Example fix
// before
parseProviderManifestDeepLinkPayload("https://provider/install?manifest=...");
// after
parseProviderManifestDeepLinkPayload("ccr://provider/install?manifest=..."); Defensive patterns
Strategy: try-catch
Validate before calling
if (!rawUrl.trim().toLowerCase().startsWith(`${appDeepLinkProtocol}://`)) throw new TypeError("not a ccr link"); Type guard
const isCcrLink = (u: string) => new URL(u.trim()).protocol === "ccr:";
Try / catch
try { parseProviderManifestDeepLinkPayload(url); } catch (e) { if (e instanceof Error && e.message === "Unsupported link protocol.") return ignore(url); throw e; } Prevention
- Build links from the exported appDeepLinkProtocol constant
- Route OS deep-link events through a scheme check first
When it happens
Trigger: Calling parseProviderManifestDeepLinkPayload with a URL whose url.protocol !== 'ccr:' — e.g. an https:// web link, a differently-prefixed custom scheme, or a leading whitespace/scheme typo surviving trim.
Common situations: Passing a regular web URL by mistake; OS rewrote or prefixed the custom scheme; scheme renamed between app versions; copy-paste dropped the 'ccr://' prefix so URL() inferred another protocol.
Related errors
- Unsupported provider protocol: ${value}
- Provider link is too long.
- Unsupported CCR link target.
- Provider payload must be a JSON object.
- ${label} is too long.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/734aa60dd885299a.
Report an issue: GitHub.