can1357/oh-my-pi · error · Error
Marketplace "${catalog.name}" already exists
Error message
Marketplace "${catalog.name}" already exists What it means
addMarketplace fetches a new marketplace source and refuses to register it if a marketplace with the same catalog name already exists in the registry. It cleans up any temporary clone before throwing. Registry entries are keyed by catalog name, so duplicates would be ambiguous.
Source
Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts:102
const extra = this.#opts.projectInstalledRegistryPath
? ([this.#opts.projectInstalledRegistryPath] as readonly string[])
: undefined;
this.#opts.clearPluginRootsCache?.(extra);
}
// ── Marketplace lifecycle ─────────────────────────────────────────────────
async addMarketplace(source: string): Promise<MarketplaceRegistryEntry> {
const reg = await readMarketplacesRegistry(this.#opts.marketplacesRegistryPath);
const existingNames = new Set(reg.marketplaces.map(m => m.name));
const { catalog, clonePath } = await fetchMarketplace(source, this.#opts.marketplacesCacheDir);
if (existingNames.has(catalog.name)) {
if (clonePath) {
await fs.rm(clonePath, { recursive: true, force: true }).catch(() => {});
}
throw new Error(`Marketplace "${catalog.name}" already exists`);
}
// Promote the temp clone to its final cache location now that we know it's not a duplicate.
if (clonePath) {
await promoteCloneToCache(clonePath, this.#opts.marketplacesCacheDir, catalog.name);
}
const sourceType = classifySource(source);
const normalizedSource = sourceType === "local" ? path.resolve(expandTilde(source)) : source;
const catalogPath = path.resolve(
expandTilde(path.join(this.#opts.marketplacesCacheDir, catalog.name, "marketplace.json")),
);
// Persist the fetched catalog so subsequent reads don't require re-fetching.
await Bun.write(catalogPath, `${JSON.stringify(catalog, null, 2)}\n`);
const now = new Date().toISOString();View on GitHub (pinned to 9690622007)
Solutions
- If you want to refresh the existing marketplace, use updateMarketplace(name) instead of addMarketplace.
- If the sources are genuinely different, rename the `name` field in one catalog so they are distinct.
- Remove the existing marketplace first (removeMarketplace) and then re-add the desired source.
Example fix
// before: duplicate add
await manager.addMarketplace("https://example.com/marketplace.json"); // name "community" exists
// after: update instead
await manager.updateMarketplace("community"); Defensive patterns
Strategy: try-catch
Validate before calling
const reg = JSON.parse(await Bun.file(registryPath).text());
// after fetching/parsing the new catalog locally:
if (reg.marketplaces.some(m => m.name === catalogName)) {
console.warn(`Marketplace "${catalogName}" already registered — call updateMarketplace instead`);
} Try / catch
try {
await manager.addMarketplace(source);
} catch (err) {
if ((err as Error).message.includes("already exists")) {
// either treat as success (idempotent add) or route to updateMarketplace
} else throw err;
} Prevention
- Make add operations idempotent in scripts: catch this and call updateMarketplace.
- Avoid registering multiple catalogs that share the same `name`; rename forks/mirrors.
- Check the registry listing before adding in interactive tools.
When it happens
Trigger: MarketplaceManager.addMarketplace(source) called when the fetched catalog's `name` matches an entry already in the marketplaces registry — e.g. re-adding the same marketplace, or two different sources whose catalogs declare the same name.
Common situations: Running an add command twice; two forks of the same marketplace both named "community"; a curated marketplace and a personal mirror sharing a name; the built-in marketplace already registered and the user adding a source with the same name.
Related errors
- Marketplace catalog name changed from "${name}" to "${catalo
- Marketplace "${name}" not found
- Marketplace "${marketplace}" not found
- Marketplace "${entry.name}" already exists
- arm '${req.arm}' already exists in '${experimentId}'
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/293297cd9c6acff7.
Report an issue: GitHub.