can1357/oh-my-pi · error · Error
Invalid plugin ID: "${pluginId}". Expected "name@marketplace
Error message
Invalid plugin ID: "${pluginId}". Expected "name@marketplace". What it means
MarketplaceManager.upgradePlugin() requires a fully qualified plugin ID of the form "name@marketplace". Before doing any registry lookup it runs parsePluginId(), and if the ID cannot be split into a plugin name and a marketplace name it throws this error immediately. This is a fail-fast input validation so the upgrade can unambiguously locate the plugin in a specific marketplace.
Source
Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts:683
isNewer = Bun.semver.order(catalogVersion, installed.version) > 0;
} catch {
isNewer = catalogVersion !== installed.version;
}
if (isNewer) {
updates.push({ pluginId, scope, from: installed.version, to: catalogVersion });
}
}
}
return updates;
}
// Re-install a specific plugin at the latest catalog version (force-overwrites).
async upgradePlugin(pluginId: string, scope?: "user" | "project"): Promise<InstalledPluginEntry> {
const parsed = parsePluginId(pluginId);
if (!parsed) {
throw new Error(`Invalid plugin ID: "${pluginId}". Expected "name@marketplace".`);
}
const { userEntries, projectEntries } = await this.#findInBothRegistries(pluginId);
const inUser = userEntries && userEntries.length > 0;
const inProject = projectEntries && projectEntries.length > 0;
if (!inUser && !inProject) {
throw new Error(`Plugin "${pluginId}" is not installed`);
}
let resolvedScope: "user" | "project";
if (inUser && inProject) {
if (!scope) {
throw new Error(
`Plugin "${pluginId}" is installed in both user and project scope. Use --scope user or --scope project to specify which to upgrade.`,
);
}View on GitHub (pinned to 9690622007)
Solutions
- Include the marketplace in the ID: call upgradePlugin("my-plugin@official") instead of upgradePlugin("my-plugin").
- Check the installed plugin entry (e.g. from listInstalledPlugins()) and use its exact id field, which is already in name@marketplace form.
- If the ID is user-supplied, validate it matches /[^@]+@[^@]+/ before calling and prompt or error with a helpful message.
- If the marketplace name is unknown, list available marketplaces first and pick the one the plugin was installed from.
Example fix
// before
await manager.upgradePlugin("my-plugin");
// after
await manager.upgradePlugin("my-plugin@official"); Defensive patterns
Strategy: validation
Validate before calling
function isValidPluginId(id: string): boolean {
const at = id.indexOf("@");
return at > 0 && at < id.length - 1 && !id.slice(at + 1).includes("@");
}
if (!isValidPluginId(pluginId)) throw new Error(`Plugin ID must be "name@marketplace", got: "${pluginId}"`);
await manager.upgradePlugin(pluginId, scope); Type guard
function isPluginId(value: string): value is `${string}@${string}` {
const at = value.indexOf("@");
return at > 0 && at < value.length - 1;
} Try / catch
try {
await manager.upgradePlugin(pluginId, scope);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Invalid plugin ID:")) {
console.error(`Bad plugin id "${pluginId}" — use name@marketplace form.`);
} else throw err;
} Prevention
- Always build plugin IDs as `${name}@${marketplace}` from structured data, never by hand.
- Take the id verbatim from a listing API's entry.id instead of retyping it.
- Validate the name@marketplace pattern in CLI argument parsing before reaching the manager.
- Keep marketplace names in a config constant to avoid typos in the @marketplace segment.
When it happens
Trigger: Calling upgradePlugin(pluginId) with a bare plugin name ("my-plugin"), an empty string, a malformed ID like "name@" or "@marketplace", or any string that parsePluginId() cannot split on a valid '@' separator.
Common situations: Users copy a plugin name from a list without its marketplace suffix; scripts pass a CLI argument that was only the plugin name; a shell script strips the @marketplace portion during quoting/escaping; or the ID comes from a stale config where the marketplace was removed.
Related errors
- Invalid package name: ${name}
- Invalid characters in package name: ${name}
- Invalid path: ${localPath} resolves outside working director
- package.json must have a valid name field
- Invalid package name: ${name}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0b1ac879e5adf41b.
Report an issue: GitHub.