musistudio/claude-code-router · warning
[deep-link] Plugin app URL was not reachable on the running
Error message
[deep-link] Plugin app URL was not reachable on the running gateway; restarting gateway once. ${formatError(error)} What it means
The plugin app URL health check against the running CCR gateway failed, so the code logs a warning and restarts the gateway once as a recovery step. This indicates the gateway is up but not serving the expected plugin route.
Source
Thrown at packages/electron/src/main/deep-link.ts:197
app.setAsDefaultProtocolClient(appDeepLinkProtocol);
} catch (error) {
console.warn(`[deep-link] Failed to register ${appDeepLinkProtocol} protocol: ${formatError(error)}`);
}
}
}
async function ensurePluginAppUrlAvailable(config: AppConfig, appUrl: string, startedGateway: boolean): Promise<void> {
try {
await waitForPluginAppUrl(
appUrl,
startedGateway ? pluginAppStartupProbeTimeoutMs : pluginAppExistingGatewayProbeTimeoutMs
);
return;
} catch (error) {
if (startedGateway) {
throw error;
}
console.warn(`[deep-link] Plugin app URL was not reachable on the running gateway; restarting gateway once. ${formatError(error)}`);
}
const restartedStatus = await gatewayService.start(config);
if (restartedStatus.state !== "running") {
throw new Error(restartedStatus.lastError || "CCR gateway did not restart.");
}
await waitForPluginAppUrl(appUrl, pluginAppStartupProbeTimeoutMs);
}
async function ensureClaudeDesignWindowCdpOptions(
config: AppConfig,
pluginId: string,
startedGateway: boolean
): ReturnType<typeof loadClaudeDesignWindowCdpOptions> {
try {
return await loadClaudeDesignWindowCdpOptions(config, pluginId);
} catch (error) {
if (startedGateway) {View on GitHub (pinned to 99f24806c6)
Solutions
- Let the automatic one-shot restart run; if it succeeds the error self-heals
- Manually stop the gateway process and retry the deep link
- Reinstall/redeploy the plugin so the gateway serves its route
- Check gateway logs for route registration failures
Defensive patterns
Strategy: retry
Validate before calling
const ok = await fetch(appUrl, { method: 'HEAD' }).then(r => r.ok).catch(() => false); if (!ok) await gatewayService.restart(); Try / catch
catch (error) { if (!startedGateway) { warn; await restartGatewayOnce(); } else throw error; } Prevention
- Health-check the plugin URL before opening deep links
- Start gateway before installing plugin deep links
- Monitor gateway version drift
When it happens
Trigger: openPluginRequest fires, gatewayService reports already running (startedGateway=false), but fetching the plugin app URL throws or times out — e.g. stale gateway process serving an old build without the plugin route.
Common situations: Gateway binary upgraded while old process still running, plugin installed after gateway start, port occupied by a zombie process, or a slow gateway still initializing its route table.
Related errors
- [deep-link] Claude browser plugin status was not reachable o
- Artifact origin is not the configured CCR gateway.
- Artifact URL does not use the CCR media artifact path.
- ${productName} is only available in CCR Desktop.
- ${productName} runtime module was not found. Rebuild app ass
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/ccb82d890a5a0bea.
Report an issue: GitHub.