can1357/oh-my-pi · error · ValueError
Plugin '${name}' is not registered
Error message
Plugin '${name}' is not registered What it means
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.
Source
Thrown at packages/mnemopi/src/core/plugins.ts:280
export class PluginManager {
private readonly registry = new Map<string, PluginConstructor>();
private readonly instances = new Map<string, MnemopiPlugin>();
constructor(private readonly pluginDir = DEFAULT_PLUGIN_DIR) {
this.registerPlugin("logging", LoggingPlugin);
this.registerPlugin("metrics", MetricsPlugin);
this.registerPlugin("filter", FilterPlugin);
this.registerPlugin("compression", CompressionPlugin);
}
registerPlugin(name: string, pluginClass: PluginConstructor): void {
if (typeof pluginClass !== "function" || !(pluginClass.prototype instanceof MnemopiPlugin)) {
throw new TypeError("pluginClass must be a MnemopiPlugin subclass");
}
if (this.registry.has(name)) throw new ValueError(`Plugin '${name}' is already registered`);
this.registry.set(name, pluginClass);
}
loadPlugin(name: string, config: PluginConfig = {}): MnemopiPlugin {
const pluginClass = this.registry.get(name);
if (pluginClass === undefined) throw new ValueError(`Plugin '${name}' is not registered`);
if (this.instances.has(name)) throw new Error(`Plugin '${name}' is already loaded`);
const instance = new pluginClass(config);
instance.initialize();
this.instances.set(name, instance);
return instance;
}
unloadPlugin(name: string): void {
const instance = this.instances.get(name);
if (instance === undefined) throw new ValueError(`Plugin '${name}' is not loaded`);
this.instances.delete(name);
instance.shutdown();
}
listPlugins(): Array<Record<string, unknown>> {
const result: Array<Record<string, unknown>> = [];
for (const [name, pluginClass] of this.registry)
result.push({
name,
class: pluginClass.name,View on GitHub (pinned to 9690622007)
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"
Example fix
// before
manager.loadPlugin("search"); // ValueError: not registered
// after
manager.registerPlugin("search", SearchPlugin);
manager.loadPlugin("search"); Defensive patterns
Strategy: validation
Validate before calling
const known = new Set(manager.listPlugins().map(p => p.name));
if (!known.has("search")) manager.registerPlugin("search", SearchPlugin);
manager.loadPlugin("search"); Try / catch
try {
manager.loadPlugin(name);
} catch (err) {
if (err instanceof ValueError && err.message.includes("not registered")) {
console.error(`Plugin "${name}" unknown; available:`, manager.listPlugins().map(p => p.name));
}
throw err;
} Prevention
- 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
When it happens
Trigger: Calling manager.loadPlugin("search") (or getPlugin/plugin/loadAll with that name) when "search" was never passed to registerPlugin; misspelling a registered plugin name.
Common situations: 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").
Related errors
- Plugin '${name}' is not loaded
- Plugin '${name}' is already loaded
- DAP adapter ${this.adapter.name} is not running
- Debug session ${root.id} is still active. Terminate it befor
- Cannot ${action} on a disposed JS runtime
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3710e4bd715f6e69.
Report an issue: GitHub.