can1357/oh-my-pi · error · Error
Cannot resolve relative source "${source}": marketplaceClone
Error message
Cannot resolve relative source "${source}": marketplaceClonePath is required What it means
Relative plugin sources are resolved against the marketplace's local clone directory. resolveRelativeSource() reads that directory from context.marketplaceClonePath; when the caller did not supply one (no clone exists or the context was built without it), it throws this error because the relative path has nothing to resolve against.
Source
Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/source-resolver.ts:60
if (typeof source === "string") {
return resolveRelativeSource(source, context);
}
return resolveObjectSource(source, context);
}
// ── Relative string source ("./plugins/foo") ────────────────────────
async function resolveRelativeSource(
source: string,
context: ResolveContext,
): Promise<{ dir: string; tempCloneRoot?: string }> {
if (!source.startsWith("./")) {
throw new Error(`Relative plugin source paths must start with "./" — got: "${source}"`);
}
if (!context.marketplaceClonePath) {
throw new Error(`Cannot resolve relative source "${source}": marketplaceClonePath is required`);
}
// If pluginRoot is set, prepend it to the path segment after "./"
const pluginRoot = context.catalogMetadata?.pluginRoot;
const relativePath = pluginRoot ? `./${path.join(pluginRoot, source.slice(2))}` : source;
// Resolve against marketplace root (not the .claude-plugin/ catalog subdirectory)
const resolved = path.resolve(context.marketplaceClonePath, relativePath);
if (!pathIsWithin(context.marketplaceClonePath, resolved)) {
throw new Error(
`Plugin source "${source}" resolves outside marketplace root ("${context.marketplaceClonePath}")`,
);
}
await verifyDirExists(resolved, `Plugin source directory does not exist: "${resolved}"`);
return { dir: resolved };
}View on GitHub (pinned to 9690622007)
Solutions
- Run the marketplace update/clone step first so marketplaceClonePath exists, then retry the install
- Re-add the marketplace to force a fresh clone if the directory was deleted
- If embedding the resolver, pass marketplaceClonePath in the ResolveContext
- Check for a prior clone failure (network/disk) that left the context incomplete
Example fix
// before
const dir = await resolvePluginSource("./plugins/foo", { catalogMetadata }); // no clonePath
// after
const dir = await resolvePluginSource("./plugins/foo", {
marketplaceClonePath: "~/.omp/marketplaces/community",
catalogMetadata,
}); Defensive patterns
Strategy: validation
Validate before calling
function canResolveRelative(ctx) {
return Boolean(ctx.marketplaceClonePath);
}
if (!canResolveRelative(ctx)) await cloneOrUpdateMarketplace(marketplaceName); Type guard
const hasClonePath = (ctx) => typeof ctx?.marketplaceClonePath === 'string' && ctx.marketplaceClonePath.length > 0;
Try / catch
try {
const dir = await resolvePluginSource(source, ctx);
} catch (err) {
if (err.message.includes('marketplaceClonePath is required')) {
await updateMarketplace(marketplaceName); // materialize the clone
// rebuild ctx and retry once
} else throw err;
} Prevention
- Always clone/update a marketplace before installing its "./"-relative plugins
- When building ResolveContext manually, include marketplaceClonePath for relative sources
- Investigate earlier clone failures (network/disk) that leave the context without a path
- Don't delete clone directories while installs may still reference them
When it happens
Trigger: Calling resolvePluginSource() for a "./..." source with a ResolveContext lacking marketplaceClonePath — e.g. resolving before the marketplace was cloned/updated, or constructing the context manually and omitting the field after a failed clone.
Common situations: Installing a plugin from a marketplace whose clone directory was deleted; a marketplace update failed leaving no local clone; SDK/API usage building ResolveContext by hand without the clone path; running an install before the first marketplace sync.
Related errors
- project-scoped install requires running inside a project dir
- Marketplace "${entry.name}" already exists
- Marketplace "${name}" not found
- Plugin "${id}" not found in registry
- Relative plugin source paths must start with "./" — got: "${
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/6af671647b04c4e7.
Report an issue: GitHub.