{"record":{"id":"21b4c635af4ccb00","repo":"can1357/oh-my-pi","slug":"marketplace-entry-name-already-exists","errorCode":null,"errorMessage":"Marketplace \"${entry.name}\" already exists","messagePattern":"Marketplace \"(.+?)\" already exists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/marketplace/registry.ts","lineNumber":136,"sourceCode":"\t\t// Accept any numeric version — forward compatible reads\n\t\treturn { ...data, version: 2 };\n\t} catch (err) {\n\t\tif (isEnoent(err)) return emptyInstalledPluginsRegistry();\n\t\tthrow err;\n\t}\n}\n\nexport async function writeInstalledPluginsRegistry(filePath: string, reg: InstalledPluginsRegistry): Promise<void> {\n\tawait atomicWriteJson(filePath, reg);\n}\n\n// ── Marketplace CRUD ─────────────────────────────────────────────────\n// Pure functions that transform registry state. Caller is responsible for\n// reading, mutating, and writing back.\n\nexport function addMarketplaceEntry(reg: MarketplacesRegistry, entry: MarketplaceRegistryEntry): MarketplacesRegistry {\n\tif (reg.marketplaces.some(m => m.name === entry.name)) {\n\t\tthrow new Error(`Marketplace \"${entry.name}\" already exists`);\n\t}\n\treturn { ...reg, marketplaces: [...reg.marketplaces, entry] };\n}\n\nexport function removeMarketplaceEntry(reg: MarketplacesRegistry, name: string): MarketplacesRegistry {\n\tconst filtered = reg.marketplaces.filter(m => m.name !== name);\n\tif (filtered.length === reg.marketplaces.length) {\n\t\tthrow new Error(`Marketplace \"${name}\" not found`);\n\t}\n\treturn { ...reg, marketplaces: filtered };\n}\n\nexport function getMarketplaceEntry(reg: MarketplacesRegistry, name: string): MarketplaceRegistryEntry | undefined {\n\treturn reg.marketplaces.find(m => m.name === name);\n}\n\n// ── Installed plugin CRUD ────────────────────────────────────────────\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/marketplace/registry.ts#L118-L154","documentation":"addMarketplaceEntry() is a pure registry transform that enforces unique marketplace names. If the registry already contains a marketplace with the same name, it throws instead of silently overwriting the existing entry (which would lose the old source/catalogPath). Callers are expected to remove or update the entry explicitly.","triggerScenarios":"Calling addMarketplaceEntry() with a name already present in reg.marketplaces — e.g. re-running a \"marketplace add\" for an existing marketplace, or an update flow that adds instead of replacing.","commonSituations":"Re-running a setup script that adds marketplaces idempotently but does not check existence; adding a marketplace whose name collides with a previously registered one from a different source; a partially-failed update that left the entry in place.","solutions":["Check existence first with getMarketplaceEntry() and skip or replace the entry","Remove the existing marketplace (removeMarketplaceEntry) then re-add with the desired source","Use an update flow that mutates the existing entry in place instead of appending","Choose a different marketplace name if both sources are wanted"],"exampleFix":"// before\nreg = addMarketplaceEntry(reg, entry); // throws if exists\n// after\nif (!getMarketplaceEntry(reg, entry.name)) {\n  reg = addMarketplaceEntry(reg, entry);\n} else {\n  reg = removeMarketplaceEntry(reg, entry.name);\n  reg = addMarketplaceEntry(reg, entry);\n}","handlingStrategy":"validation","validationCode":"import { getMarketplaceEntry, addMarketplaceEntry, removeMarketplaceEntry } from './registry';\nif (getMarketplaceEntry(reg, entry.name)) {\n  reg = removeMarketplaceEntry(reg, entry.name);\n}\nreg = addMarketplaceEntry(reg, entry);","typeGuard":"null","tryCatchPattern":"try {\n  reg = addMarketplaceEntry(reg, entry);\n} catch (err) {\n  if (err.message === `Marketplace \"${entry.name}\" already exists`) {\n    reg = removeMarketplaceEntry(reg, entry.name);\n    reg = addMarketplaceEntry(reg, entry); // replace\n  } else throw err;\n}","preventionTips":["Make add-marketplace scripts idempotent with an existence check","Pick unique marketplace names when registering multiple sources","Use the update flow for existing marketplaces instead of add","Check getMarketplaceEntry before re-running setup scripts"],"tags":["plugin","duplicate","registry"],"backgroundTag":"duplicate-marketplace-entry","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}