can1357/oh-my-pi · error · Error

Plugin "${pluginId}" is not installed

Error message

Plugin "${pluginId}" is not installed

What it means

After validating the id format, uninstallPlugin checks both user and project installed-plugin registries via #findInBothRegistries. If the plugin id has no entries in either scope, there is nothing to remove and it throws this error.

Source

Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts:457

			return entry.source.sha.slice(0, 7);
		}

		return "0.0.0";
	}

	/** Validates and removes a marketplace plugin, or only validates when `dryRun` is set. */
	async uninstallPlugin(pluginId: string, scope?: "user" | "project", options?: { dryRun?: boolean }): Promise<void> {
		const parsed = parsePluginId(pluginId);
		if (!parsed) {
			throw new Error(`Invalid plugin ID format: "${pluginId}". Expected "name@marketplace".`);
		}

		const { userEntries, projectEntries, userReg, projectReg } = await this.#findInBothRegistries(pluginId);
		const inUser = userEntries && userEntries.length > 0;
		const inProject = projectEntries && projectEntries.length > 0;

		if (!inUser && !inProject) {
			throw new Error(`Plugin "${pluginId}" is not installed`);
		}

		// Disambiguation: if installed in both scopes and no explicit scope, require one.
		let targetScope: "user" | "project";
		if (inUser && inProject) {
			if (!scope) {
				throw new Error(
					`Plugin "${pluginId}" is installed in both user and project scope. Use --scope user or --scope project to specify which to remove.`,
				);
			}
			targetScope = scope;
		} else if (inProject) {
			if (scope === "user") {
				throw new Error(`Plugin "${pluginId}" is not installed in user scope`);
			}
			targetScope = "project";
		} else {
			if (scope === "project") {

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the exact installed id via the plugin list for both scopes, then retry
  2. Run from the correct project directory if the plugin was installed in project scope
  3. If already uninstalled, no action needed — treat this as success in idempotent scripts
  4. Check that the @marketplace part matches where the plugin was installed from

Example fix

// before
await manager.uninstallPlugin("formatter@old-marketplace");
// after
await manager.uninstallPlugin("formatter@community"); // id confirmed via installed-plugins list
Defensive patterns

Strategy: validation

Validate before calling

const installed = await manager.listInstalledPlugins(); // both scopes
const target = `${name}@${marketplace}`;
if (!installed.some(p => p.id === target)) {
  console.log(`${target} is not installed; nothing to do`);
  return;
}
await manager.uninstallPlugin(target);

Try / catch

try {
  await manager.uninstallPlugin(pluginId);
} catch (err) {
  if (err instanceof Error && err.message.includes("is not installed")) {
    // idempotent uninstall: already gone, treat as success
  } else throw err;
}

Prevention

When it happens

Trigger: uninstallPlugin("name@marketplace") where neither the user-scope nor project-scope registry contains that id — plugin never installed, already uninstalled, wrong marketplace suffix, or wrong working directory (project registry is project-scoped).

Common situations: Uninstalling from a different project directory than the one where the plugin was project-installed; double-uninstall after the first succeeded; marketplace suffix mismatch (installed from "acme" but uninstalling "name@other").

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/44dd962c29867ad5. Report an issue: GitHub.