musistudio/claude-code-router · error · Error

${productName} runtime module was not found. Rebuild app ass

Error message

${productName} runtime module was not found. Rebuild app assets so the bundled ${productName} plugin is copied into the Electron dist.

What it means

Thrown by the desktop config writer when the bundled ${productName} (CCR) runtime plugin config cannot be resolved via claudeProductRuntimePluginConfig(pluginId). It means the app is running in the CCR Desktop (Electron) runtime, but the plugin module that should ship inside the Electron dist assets is missing, typically because app assets were built without copying the bundled plugin.

Source

Thrown at packages/core/src/config/config.ts:2994

export function withClaudeDesignRuntimePluginConfig(config: AppConfig): AppConfig {
  return withClaudeProductRuntimePluginConfig(config, CLAUDE_DESIGN_PLUGIN_ID, "Claude Design");
}

export function withClaudeShipRuntimePluginConfig(config: AppConfig): AppConfig {
  return withClaudeProductRuntimePluginConfig(config, CLAUDE_SHIP_PLUGIN_ID, "Claude Ship");
}

function withClaudeProductRuntimePluginConfig(config: AppConfig, pluginId: string, productName: string): AppConfig {
  const existingIndex = config.plugins.findIndex((plugin) => plugin.enabled !== false && plugin.id === pluginId);
  if (existingIndex >= 0 && config.plugins[existingIndex]?.module?.trim()) {
    return config;
  }
  if (!isDesktopAppRuntime()) {
    throw new Error(`${productName} is only available in CCR Desktop.`);
  }
  const plugin = claudeProductRuntimePluginConfig(pluginId);
  if (!plugin) {
    throw new Error(`${productName} runtime module was not found. Rebuild app assets so the bundled ${productName} plugin is copied into the Electron dist.`);
  }
  if (existingIndex >= 0) {
    const existing = config.plugins[existingIndex];
    const plugins = [...config.plugins];
    plugins[existingIndex] = {
      ...plugin,
      ...existing,
      apps: existing.apps ?? plugin.apps,
      module: plugin.module,
      permissions: existing.permissions ?? plugin.permissions,
      surfaces: existing.surfaces ?? plugin.surfaces
    };
    return {
      ...config,
      plugins
    };
  }
  return {

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Rebuild the app assets (the build step that copies the bundled CCR plugin into the Electron dist) and restart the app
  2. Clear stale build output (dist/, out/, electron build cache) and rebuild from clean
  3. Reinstall/upgrade CCR Desktop so the plugin ships with the matching version
  4. If developing locally, verify the plugin id exists in the bundled plugin manifest used by claudeProductRuntimePluginConfig
Defensive patterns

Strategy: type-guard

Validate before calling

if (isDesktopAppRuntime() && !claudeProductRuntimePluginConfig(pluginId)) { /* rebuild assets before proceeding */ }

Type guard

const hasRuntimePlugin = (id: string) =>
  isDesktopAppRuntime() && claudeProductRuntimePluginConfig(id) !== undefined;

Try / catch

try { applyPlugin(config, pluginId); } catch (e) { if (e instanceof Error && /runtime module was not found/.test(e.message)) { await rebuildAssets(); } else throw e; }

Prevention

When it happens

Trigger: Calling the config API that installs/updates the ${productName} runtime plugin (isDesktopAppRuntime() returns true) after isDesktopAppRuntime check passes, but claudeProductRuntimePluginConfig(pluginId) returns undefined because the plugin was never copied into the Electron dist.

Common situations: Running a dev build of the Electron app without rebuilding assets; CI builds that skip the asset-copy step; upgrading CCR Desktop where the dist layout changed and the plugin is no longer bundled; stale node_modules/electron dist after a version bump.

Related errors


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