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

  1. Let the automatic one-shot restart run; if it succeeds the error self-heals
  2. Manually stop the gateway process and retry the deep link
  3. Reinstall/redeploy the plugin so the gateway serves its route
  4. 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

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


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/ccb82d890a5a0bea. Report an issue: GitHub.