jackwener/OpenCLI · error · PluginError

Monorepo manifest missing or invalid at ${repoRoot}

Error message

Monorepo manifest missing or invalid at ${repoRoot}

What it means

When installing/updating from a monorepo plugin source, opencli reads the manifest either from the already-installed repo directory or from a freshly cloned copy and validates it with isMonorepo. If the manifest is missing or does not have the expected monorepo shape (e.g. a plugins map), it throws. This ensures the repo actually is a multi-plugin monorepo before iterating its sub-plugins.

Source

Thrown at src/plugin.ts:860

  writeLockFile(lock);
}

/** Install sub-plugins from a monorepo. */
function installMonorepo(
  cloneDir: string,
  cloneUrl: string,
  repoName: string,
  manifest: PluginManifest,
  subPlugin?: string,
): string[] {
  const monoreposDir = getMonoreposDir();
  const repoDir = path.join(monoreposDir, repoName);
  const repoAlreadyInstalled = fs.existsSync(repoDir);
  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(', ')}`
      );
    }
  }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the repo URL/name points at a plugin monorepo containing a valid manifest with a plugins section.
  2. Delete the existing installed repo directory under the monorepos/plugins dir so a fresh clone and manifest read occurs.
  3. Check the upstream repo: restore or fix the root plugin manifest, and confirm you cloned the intended branch/tag.
  4. If installing a specific sub-plugin, confirm the sub-plugin name exists in the monorepo manifest's plugins map.

Example fix

// before: manifest missing plugins map
{ "name": "my-mono-repo" }
// after
{ "name": "my-mono-repo", "plugins": { "core": { "path": "packages/core" } } }
Defensive patterns

Strategy: validation

Validate before calling

const manifestPath = path.join(cloneDir, 'opencli.json');
if (!fs.existsSync(manifestPath)) throw new Error(`No manifest at ${cloneDir}`);
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
if (!manifest.plugins || typeof manifest.plugins !== 'object') {
  throw new Error(`${cloneDir} is not a plugin monorepo`);
}

Type guard

function isMonorepoManifest(m: unknown): m is { plugins: Record<string, unknown> } {
  return !!m && typeof m === 'object' && 'plugins' in m && typeof (m as any).plugins === 'object';
}

Try / catch

try {
  await opencli.plugin.installFromMonorepo(repo, subPlugin);
} catch (e) {
  if (e.message.includes('Monorepo manifest missing or invalid')) {
    console.error(`Verify ${repo} is a plugin monorepo with a valid root manifest.`);
  } else throw e;
}

Prevention

When it happens

Trigger: Installing a plugin by monorepo name/repo URL where the cloned repo has no plugin manifest at its root, the manifest is malformed JSON, or it lacks the required monorepo fields (isMonorepo returns false) — including when reusing an existing installed repoDir whose manifest has become unreadable.

Common situations: Wrong repo URL (a normal single-plugin repo or a non-plugin repo); manifest file renamed/deleted upstream; clone of an empty or wrong branch; corrupted prior install directory whose manifest can no longer be read.

Related errors


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