{"record":{"id":"286a0c90500b93f4","repo":"can1357/oh-my-pi","slug":"invalid-plugin-id-format-pluginid-expected","errorCode":null,"errorMessage":"Invalid plugin ID format: \"${pluginId}\". Expected \"name@marketplace\".","messagePattern":"Invalid plugin ID format: \"(.+?)\"\\. Expected \"name@marketplace\"\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts","lineNumber":449,"sourceCode":"\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Missing or invalid — try next\n\t\t\t}\n\t\t}\n\n\t\t// 3. Git SHA from source definition\n\t\tif (typeof entry.source === \"object\" && \"sha\" in entry.source && entry.source.sha) {\n\t\t\treturn entry.source.sha.slice(0, 7);\n\t\t}\n\n\t\treturn \"0.0.0\";\n\t}\n\n\t/** Validates and removes a marketplace plugin, or only validates when `dryRun` is set. */\n\tasync uninstallPlugin(pluginId: string, scope?: \"user\" | \"project\", options?: { dryRun?: boolean }): Promise<void> {\n\t\tconst parsed = parsePluginId(pluginId);\n\t\tif (!parsed) {\n\t\t\tthrow new Error(`Invalid plugin ID format: \"${pluginId}\". Expected \"name@marketplace\".`);\n\t\t}\n\n\t\tconst { userEntries, projectEntries, userReg, projectReg } = await this.#findInBothRegistries(pluginId);\n\t\tconst inUser = userEntries && userEntries.length > 0;\n\t\tconst inProject = projectEntries && projectEntries.length > 0;\n\n\t\tif (!inUser && !inProject) {\n\t\t\tthrow new Error(`Plugin \"${pluginId}\" is not installed`);\n\t\t}\n\n\t\t// Disambiguation: if installed in both scopes and no explicit scope, require one.\n\t\tlet targetScope: \"user\" | \"project\";\n\t\tif (inUser && inProject) {\n\t\t\tif (!scope) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Plugin \"${pluginId}\" is installed in both user and project scope. Use --scope user or --scope project to specify which to remove.`,\n\t\t\t\t);\n\t\t\t}","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts#L431-L467","documentation":"uninstallPlugin requires the plugin to be identified as \"name@marketplace\". It runs parsePluginId(pluginId) and throws when the string does not match that format. This prevents ambiguous deletions where a bare name could match plugins from multiple marketplaces.","triggerScenarios":"Calling uninstallPlugin with an id missing the @marketplace suffix, containing extra @ separators the parser rejects, or being empty/whitespace — e.g. uninstallPlugin(\"formatter\") instead of uninstallPlugin(\"formatter@community\").","commonSituations":"Users typing just the plugin name on the CLI; scripts passing a name copied from a display label rather than the registry id; shell quoting stripping an @ token; stale docs predating the name@marketplace convention.","solutions":["Pass the full id as \"name@marketplace\", e.g. uninstallPlugin(\"formatter@community\")","Look up the exact installed id in the installed-plugins registry (or via list) and copy it verbatim","If building the id programmatically, use buildPluginId(name, marketplace)"],"exampleFix":"// before\nawait manager.uninstallPlugin(\"formatter\");\n// after\nawait manager.uninstallPlugin(\"formatter@community\");","handlingStrategy":"validation","validationCode":"function isValidPluginId(id: string): boolean {\n  const at = id.lastIndexOf(\"@\");\n  return at > 0 && at < id.length - 1 && !id.slice(0, at).includes(\"@\") === false || at > 0; // keep simple:\n}\n// simpler:\nif (!/^[^@\\s]+@[^@\\s]+$/.test(pluginId)) throw new Error(`need name@marketplace, got ${pluginId}`);\nawait manager.uninstallPlugin(pluginId);","typeGuard":"function isPluginId(v: string): boolean {\n  const m = /^([^@\\s]+)@([^@\\s]+)$/.exec(v);\n  return !!m;\n}","tryCatchPattern":"try {\n  await manager.uninstallPlugin(rawArg);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"Invalid plugin ID format\")) {\n    console.error(`Usage: omp plugin uninstall <name>@<marketplace> (got \"${rawArg}\")`);\n  } else throw err;\n}","preventionTips":["Always build ids with buildPluginId(name, marketplace) instead of string concatenation","Quote \"name@marketplace\" arguments in shell scripts so @ parsing quirks don't bite","Validate user input against /^[^@]+@[^@]+$/ before calling uninstallPlugin","Show id format in CLI help text and error hints"],"tags":["plugin-marketplace","argument-validation","format"],"backgroundTag":"invalid-plugin-id-format","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}