{"record":{"id":"3710e4bd715f6e69","repo":"can1357/oh-my-pi","slug":"plugin-name-is-not-registered","errorCode":null,"errorMessage":"Plugin '${name}' is not registered","messagePattern":"Plugin '(.+?)' is not registered","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/mnemopi/src/core/plugins.ts","lineNumber":280,"sourceCode":"export class PluginManager {\n\tprivate readonly registry = new Map<string, PluginConstructor>();\n\tprivate readonly instances = new Map<string, MnemopiPlugin>();\n\tconstructor(private readonly pluginDir = DEFAULT_PLUGIN_DIR) {\n\t\tthis.registerPlugin(\"logging\", LoggingPlugin);\n\t\tthis.registerPlugin(\"metrics\", MetricsPlugin);\n\t\tthis.registerPlugin(\"filter\", FilterPlugin);\n\t\tthis.registerPlugin(\"compression\", CompressionPlugin);\n\t}\n\tregisterPlugin(name: string, pluginClass: PluginConstructor): void {\n\t\tif (typeof pluginClass !== \"function\" || !(pluginClass.prototype instanceof MnemopiPlugin)) {\n\t\t\tthrow new TypeError(\"pluginClass must be a MnemopiPlugin subclass\");\n\t\t}\n\t\tif (this.registry.has(name)) throw new ValueError(`Plugin '${name}' is already registered`);\n\t\tthis.registry.set(name, pluginClass);\n\t}\n\tloadPlugin(name: string, config: PluginConfig = {}): MnemopiPlugin {\n\t\tconst pluginClass = this.registry.get(name);\n\t\tif (pluginClass === undefined) throw new ValueError(`Plugin '${name}' is not registered`);\n\t\tif (this.instances.has(name)) throw new Error(`Plugin '${name}' is already loaded`);\n\t\tconst instance = new pluginClass(config);\n\t\tinstance.initialize();\n\t\tthis.instances.set(name, instance);\n\t\treturn instance;\n\t}\n\tunloadPlugin(name: string): void {\n\t\tconst instance = this.instances.get(name);\n\t\tif (instance === undefined) throw new ValueError(`Plugin '${name}' is not loaded`);\n\t\tthis.instances.delete(name);\n\t\tinstance.shutdown();\n\t}\n\tlistPlugins(): Array<Record<string, unknown>> {\n\t\tconst result: Array<Record<string, unknown>> = [];\n\t\tfor (const [name, pluginClass] of this.registry)\n\t\t\tresult.push({\n\t\t\t\tname,\n\t\t\t\tclass: pluginClass.name,","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/core/plugins.ts#L262-L298","documentation":"loadPlugin looks the name up in the registry populated by registerPlugin; if the name was never registered, a ValueError is thrown. The registry only contains the built-ins (metrics, filter, compression) plus anything explicitly registered.","triggerScenarios":"Calling manager.loadPlugin(\"search\") (or getPlugin/plugin/loadAll with that name) when \"search\" was never passed to registerPlugin; misspelling a registered plugin name.","commonSituations":"Typos in plugin names; expecting all plugins to be pre-registered when only the three built-ins are; loading a plugin before calling registerPlugin on it; case mismatches (\"Filter\" vs \"filter\").","solutions":["Call registerPlugin(name, PluginClass) before loadPlugin for non-built-in plugins","Check available names with manager.listPlugins() and correct the spelling/case","Use the built-in names exactly: \"metrics\", \"filter\", \"compression\""],"exampleFix":"// before\nmanager.loadPlugin(\"search\"); // ValueError: not registered\n// after\nmanager.registerPlugin(\"search\", SearchPlugin);\nmanager.loadPlugin(\"search\");","handlingStrategy":"validation","validationCode":"const known = new Set(manager.listPlugins().map(p => p.name));\nif (!known.has(\"search\")) manager.registerPlugin(\"search\", SearchPlugin);\nmanager.loadPlugin(\"search\");","typeGuard":null,"tryCatchPattern":"try {\n  manager.loadPlugin(name);\n} catch (err) {\n  if (err instanceof ValueError && err.message.includes(\"not registered\")) {\n    console.error(`Plugin \"${name}\" unknown; available:`, manager.listPlugins().map(p => p.name));\n  }\n  throw err;\n}","preventionTips":["Register before load for every non-built-in plugin","Keep plugin names as constants/enums to avoid typos and case mismatches","List registered plugins to discover valid names at runtime"],"tags":["plugin","unregistered","lifecycle"],"backgroundTag":"plugin-not-registered","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}