jackwener/OpenCLI · error · PluginError

Sub-plugin "${subPlugin}" not found in monorepo. Available:

Error message

Sub-plugin "${subPlugin}" not found in monorepo. Available: ${Object.keys(effectiveManifest.plugins ?? {}).join(', ')}

What it means

When a requested sub-plugin name does not match any entry in the monorepo manifest's plugins map, opencli throws with the list of available sub-plugin names. This is a name-resolution failure inside a monorepo install — the repo is a valid monorepo but has no plugin with that name.

Source

Thrown at src/plugin.ts:874

  const repoRoot = repoAlreadyInstalled ? repoDir : cloneDir;
  const effectiveManifest = repoAlreadyInstalled ? readPluginManifest(repoDir) : manifest;

  if (!effectiveManifest || !isMonorepo(effectiveManifest)) {
    throw new PluginError(`Monorepo manifest missing or invalid at ${repoRoot}`);
  }

  let pluginsToInstall = getEnabledPlugins(effectiveManifest);

  // If a specific sub-plugin was requested, filter to just that one
  if (subPlugin) {
    pluginsToInstall = pluginsToInstall.filter((p) => p.name === subPlugin);
    if (pluginsToInstall.length === 0) {
      // Check if it exists but is disabled
      const disabled = effectiveManifest.plugins?.[subPlugin];
      if (disabled) {
        throw new PluginError(`Sub-plugin "${subPlugin}" is disabled in the manifest.`);
      }
      throw new PluginError(
        `Sub-plugin "${subPlugin}" not found in monorepo. Available: ${Object.keys(effectiveManifest.plugins ?? {}).join(', ')}`
      );
    }
  }

  const installedNames: string[] = [];
  const lock = readLockFile();
  const eligiblePlugins: Array<{ name: string; entry: typeof pluginsToInstall[number]['entry'] }> = [];

  fs.mkdirSync(PLUGINS_DIR, { recursive: true });

  for (const { name, entry } of pluginsToInstall) {
    // Check sub-plugin level compatibility (overrides top-level)
    if (entry.opencli && !checkCompatibility(entry.opencli)) {
      log.warn(`Skipping "${name}": requires opencli ${entry.opencli}`);
      continue;
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use an available name exactly as listed in the error's 'Available: ...' list.
  2. Check the monorepo's manifest for the current sub-plugin names (they may have been renamed upstream).
  3. If the plugin was removed upstream, pin/checkout an older repo revision or install a different plugin.

Example fix

// before
opencli plugin install my-mono/lintt
// after (from available list)
opencli plugin install my-mono/lint
Defensive patterns

Strategy: validation

Validate before calling

const manifest = JSON.parse(fs.readFileSync(path.join(cloneDir, 'opencli.json'), 'utf8'));
const available = Object.keys(manifest.plugins ?? {});
if (!available.includes(subPlugin)) {
  throw new Error(`Unknown sub-plugin "${subPlugin}". Available: ${available.join(', ')}`);
}

Type guard

function subPluginExists(m: { plugins?: Record<string, unknown> }, name: string): boolean {
  return Object.prototype.hasOwnProperty.call(m.plugins ?? {}, name);
}

Try / catch

try {
  await opencli.plugin.installFromMonorepo(repo, subPlugin);
} catch (e) {
  const m = e.message.match(/Available: (.*)/);
  if (m) console.error(`Pick one of: ${m[1]}`);
  else throw e;
}

Prevention

When it happens

Trigger: Installing from a monorepo with a sub-plugin argument that is not a key of effectiveManifest.plugins (after filtering out disabled ones via getEnabledPlugins), and the name is also not present as a disabled entry.

Common situations: Typos in the sub-plugin name; using a plugin name from a different monorepo; upstream renamed/removed the sub-plugin; case-sensitivity mismatch in the name.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/d02f4a2eb5ae879c. Report an issue: GitHub.