can1357/oh-my-pi · error · Error

Marketplace catalog not found at ${catalogPath}. Try: /marke

Error message

Marketplace catalog not found at ${catalogPath}. Try: /marketplace update ${entry.name}

What it means

When resolving a marketplace's catalog, the manager reads the catalog file recorded in the registry entry (entry.catalogPath). If the read fails with ENOENT — the file does not exist — it converts the raw filesystem error into this actionable message suggesting a /marketplace update for that marketplace. Other read/parse errors are re-thrown unchanged.

Source

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

				? readInstalledPluginsRegistry(this.#opts.projectInstalledRegistryPath)
				: Promise.resolve({ version: 2 as const, plugins: {} as Record<string, InstalledPluginEntry[]> }),
		]);
		return {
			userEntries: getInstalledPlugin(userReg, pluginId),
			projectEntries: getInstalledPlugin(projectReg, pluginId),
			userReg,
			projectReg,
		};
	}

	async #readCatalog(entry: MarketplaceRegistryEntry): Promise<MarketplaceCatalog> {
		const catalogPath = path.resolve(expandTilde(entry.catalogPath));
		try {
			const content = await Bun.file(catalogPath).text();
			return parseMarketplaceCatalog(content, catalogPath);
		} catch (err) {
			if (isEnoent(err)) {
				throw new Error(`Marketplace catalog not found at ${catalogPath}. Try: /marketplace update ${entry.name}`);
			}
			throw err;
		}
	}

	/**
	 * Compute the marketplace root directory for source resolution.
	 *
	 * For local sources: sourceUri IS the local path, so resolve it directly.
	 * This gives the directory containing `.claude-plugin/marketplace.json`,
	 * which is what resolvePluginSource expects as `marketplaceClonePath`.
	 *
	 * For remote sources (git/github/url): the catalog was cloned into
	 * `<marketplacesCacheDir>/<name>/`, so the root is the parent of catalogPath.
	 */
	#resolveMarketplaceRoot(entry: MarketplaceRegistryEntry): string {
		if (entry.sourceType === "local") {
			return path.resolve(expandTilde(entry.sourceUri));

View on GitHub (pinned to 9690622007)

Solutions

  1. Run the marketplace update command for that marketplace (e.g. /marketplace update <name>) to re-fetch the catalog
  2. Remove the marketplace (removeMarketplaceEntry / marketplace remove) and re-add it with the correct source
  3. Check that entry.catalogPath points where you expect — fix a stale path in the registry if the file exists elsewhere

Example fix

// stale registry entry
{"name": "community", "catalogPath": "/tmp/clone123/.omp-marketplace.json"}
// after re-adding / updating
{"name": "community", "catalogPath": "~/.omp/marketplaces/community/.omp-marketplace.json"}
Defensive patterns

Strategy: retry

Validate before calling

const catalogPath = path.resolve(expandTilde(entry.catalogPath));
const catalogFile = Bun.file(catalogPath);
if (!(await catalogFile.exists())) {
  await updateMarketplace(entry.name); // re-fetch catalog before install
}

Type guard

null

Try / catch

try {
  await installFromMarketplace(entry);
} catch (err) {
  if (err.message.includes('Marketplace catalog not found')) {
    const m = err.message.match(/update (\S+)$/);
    if (m) await runMarketplaceUpdate(m[1]);
    // then retry once
  } else throw err;
}

Prevention

When it happens

Trigger: The catalog file was deleted after registration; the marketplace was cloned/registered on another machine or path that no longer exists; the project was moved so the stored absolute path is stale; a fresh checkout never ran the marketplace update that materializes the catalog.

Common situations: Switching machines or restoring dotfiles without the marketplace clones; deleting the cache/clone directory to "clean up"; installing plugins from a marketplace whose catalog was registered under a temp path that got wiped.

Related errors


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