{"record":{"id":"01e16dc832f385f8","repo":"can1357/oh-my-pi","slug":"plugin-name-uses-a-relative-source-path-but-m","errorCode":null,"errorMessage":"Plugin \"${name}\" uses a relative source path but marketplace \"${marketplace}\" was added via URL. Relative sources require a git or local marketplace. Re-add the marketplace using its git URL.","messagePattern":"Plugin \"(.+?)\" uses a relative source path but marketplace \"(.+?)\" was added via URL\\. Relative sources require a git or local marketplace\\. Re-add the marketplace using its git URL\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts","lineNumber":289,"sourceCode":"\t\t}\n\n\t\t// 4. Resolve source path.\n\t\t// marketplaceClonePath is the marketplace root — the directory containing .claude-plugin/\n\t\t// catalogPath is <marketplacesCacheDir>/<name>/marketplace.json, so the root is two levels up.\n\t\t// For local sources the content was fetched from a local path; the stored catalog is a copy\n\t\t// under marketplacesCacheDir. We need the original source root for resolving relative paths.\n\t\t// Use: path.dirname(catalogPath) is <cacheDir>/<name>/, and that IS the stored copy root,\n\t\t// so `path.resolve(mktEntry.catalogPath, \"../..\")` = parent of <name>/ inside cacheDir\n\t\t// which is wrong for local sources. Instead, derive from the stored catalog directory:\n\t\t// stored at: <marketplacesCacheDir>/<catalogName>/marketplace.json\n\t\t// The marketplace root for local sources should be the actual local path, but we only have\n\t\t// sourceUri. For local sources, use path.resolve of sourceUri; for others use the cache dir.\n\t\tconst marketplaceClonePath = this.#resolveMarketplaceRoot(mktEntry);\n\n\t\t// URL-sourced marketplaces only cache marketplace.json, not the full plugin tree.\n\t\t// Relative string sources (\"./plugins/foo\") cannot be resolved against the cache dir.\n\t\tif (mktEntry.sourceType === \"url\" && typeof pluginEntry.source === \"string\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Plugin \"${name}\" uses a relative source path but marketplace \"${marketplace}\" was added via URL. ` +\n\t\t\t\t\t`Relative sources require a git or local marketplace. Re-add the marketplace using its git URL.`,\n\t\t\t);\n\t\t}\n\n\t\tconst { dir: sourcePath, tempCloneRoot } = await resolvePluginSource(pluginEntry, {\n\t\t\tmarketplaceClonePath,\n\t\t\tcatalogMetadata: catalog.metadata,\n\t\t\ttmpDir: os.tmpdir(),\n\t\t});\n\n\t\t// 5. Determine version: catalog entry > plugin manifest > git SHA > fallback\n\t\tlet version!: string;\n\t\tlet cachePath!: string;\n\t\ttry {\n\t\t\tversion = await this.#resolvePluginVersion(pluginEntry, sourcePath);\n\t\t\tcachePath = await cachePlugin(sourcePath, this.#opts.pluginsCacheDir, marketplace, name, version);\n\t\t\tawait this.#writeEmbeddedLspConfig(pluginEntry, cachePath);","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts#L271-L307","documentation":"Plugins can declare their source as a relative string path (e.g. \"./plugins/foo\") that is resolved against the marketplace root. URL-sourced marketplaces only cache marketplace.json — not the full plugin tree — so a relative source has nothing to resolve against, and installPlugin throws rather than guessing. Git- or local-sourced marketplaces have a full clone/tree and work fine.","triggerScenarios":"installPlugin(name, marketplace) where mktEntry.sourceType === \"url\" and pluginEntry.source is a string (relative path) — i.e. installing a tree-relative plugin from a marketplace that was added by raw URL to its marketplace.json.","commonSituations":"Adding a marketplace by pasting the raw github.com URL of marketplace.json instead of its git repo URL; a marketplace migrated from git to a URL source; sharing an install command that worked for a git-cloned marketplace.","solutions":["Remove and re-add the marketplace using its git URL so the full tree is cloned: removeMarketplace then addMarketplace with the repo URL","Pick the same plugin from a git- or local-sourced marketplace that publishes it with a resolvable source","If you control the marketplace, switch the plugin entry to an absolute/remote source (git URL) instead of a relative path"],"exampleFix":"// before\nawait manager.addMarketplace({ source: \"https://github.com/acme/plugins/raw/main/.claude-plugin/marketplace.json\" });\nawait manager.installPlugin(\"lint-rules\", \"acme\"); // relative \"./plugins/lint-rules\" cannot resolve\n// after\nawait manager.addMarketplace({ source: \"https://github.com/acme/plugins.git\", name: \"acme\" });\nawait manager.installPlugin(\"lint-rules\", \"acme\");","handlingStrategy":"validation","validationCode":"// Check the marketplace source type before installing relative-path plugins\nconst reg = await readMarketplacesRegistry(manager.marketplacesRegistryPath);\nconst entry = getMarketplaceEntry(reg, marketplace);\nif (entry?.sourceType === \"url\") {\n  throw new Error(`Marketplace ${marketplace} is URL-sourced; re-add via git URL to install tree plugins`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await manager.installPlugin(name, marketplace);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"relative source path\")) {\n    await manager.removeMarketplace(marketplace);\n    await manager.addMarketplace({ source: GIT_URLS[marketplace], name: marketplace });\n    await manager.installPlugin(name, marketplace);\n  } else throw err;\n}","preventionTips":["Always add marketplaces by their git repo URL, not raw marketplace.json URLs, when plugins use relative sources","Document per-marketplace whether plugins use relative paths and require git source","Prefer git-sourced marketplaces in CI/setup scripts","If authoring a marketplace, use git/remote source entries instead of relative string paths for URL-distributed catalogs"],"tags":["plugin-marketplace","url-marketplace","relative-path"],"backgroundTag":"relative-source-url-marketplace","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}