jackwener/OpenCLI · error

Installed sub-plugin "${pluginName}" no longer exists in ${c

Error message

Installed sub-plugin "${pluginName}" no longer exists in ${cloneUrl}

What it means

During monorepo plugin update, opencli re-reads the upstream manifest and iterates the installed lock entries belonging to that monorepo. If an installed sub-plugin is missing from the new manifest or is now marked disabled, it throws a plain Error because the update can no longer maintain that sub-plugin. This keeps the lock file consistent with the upstream repo.

Source

Thrown at src/plugin.ts:986

  manifest: PluginManifest,
  cloneUrl: string,
  tmpCloneDir: string,
): Array<{
  name: string;
  lockEntry: LockEntry;
  manifestEntry: NonNullable<PluginManifest['plugins']>[string];
}> {
  const updatedPlugins: Array<{
    name: string;
    lockEntry: LockEntry;
    manifestEntry: NonNullable<PluginManifest['plugins']>[string];
  }> = [];

  for (const [pluginName, entry] of Object.entries(lock)) {
    if (entry.source.kind !== 'monorepo' || entry.source.repoName !== monoName) continue;
    const manifestEntry = manifest.plugins?.[pluginName];
    if (!manifestEntry || manifestEntry.disabled) {
      throw new Error(`Installed sub-plugin "${pluginName}" no longer exists in ${cloneUrl}`);
    }
    if (manifestEntry.opencli && !checkCompatibility(manifestEntry.opencli)) {
      throw new Error(`Sub-plugin "${pluginName}" requires opencli ${manifestEntry.opencli}`);
    }

    const subDir = resolveRepoContainedPath(tmpCloneDir, manifestEntry.path);
    const validation = validatePluginStructure(subDir);
    if (!validation.valid) {
      throw new Error(`Updated sub-plugin "${pluginName}" is invalid:\n- ${validation.errors.join('\n- ')}`);
    }
    updatedPlugins.push({ name: pluginName, lockEntry: entry, manifestEntry });
  }

  return updatedPlugins;
}

function updateMonorepoLockEntries(
  lock: Record<string, LockEntry>,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Uninstall the removed/disabled sub-plugin locally so the lock no longer references it, then re-run the update.
  2. If the removal was unintended, open an issue with the monorepo maintainer or pin to the previous commit/tag.
  3. Update your local manifest/config to re-enable the plugin if it was merely disabled and you control the manifest.

Example fix

// before: update fails because 'lint' was removed upstream
opencli plugin update my-mono
// after
opencli plugin uninstall lint
opencli plugin update my-mono
Defensive patterns

Strategy: try-catch

Validate before calling

for (const name of Object.keys(lock)) {
  const entry = lock[name];
  if (entry.source.kind !== 'monorepo' || entry.source.repoName !== monoName) continue;
  if (!manifest.plugins?.[name] || manifest.plugins[name].disabled) {
    console.warn(`${name} was removed/disabled upstream; uninstall before updating`);
  }
}

Type guard

function stillProvidedUpstream(
  m: { plugins?: Record<string, { disabled?: boolean }> },
  name: string,
): boolean {
  const e = m.plugins?.[name];
  return !!e && !e.disabled;
}

Try / catch

try {
  await opencli.plugin.updateMonorepo(monoName);
} catch (e) {
  if (e.message.includes('no longer exists in')) {
    const name = e.message.match(/"(.*)"/)?.[1];
    await opencli.plugin.uninstall(name);
    await opencli.plugin.updateMonorepo(monoName);
  } else throw e;
}

Prevention

When it happens

Trigger: Running the monorepo update path after upstream removed a sub-plugin you have installed, or upstream set `disabled: true` for it in manifest.plugins — the lock entry references a pluginName absent (or disabled) in the fresh manifest.

Common situations: Repo maintainer deleted or disabled a plugin between install and update; your lock file is stale relative to a heavily refactored upstream manifest; updating on the wrong branch where the plugin doesn't exist.

Related errors


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