can1357/oh-my-pi · error · TypeError

MnemopiPlugin is abstract

Error message

MnemopiPlugin is abstract

What it means

MnemopiPlugin is an abstract base class for mnemopi plugins. Its constructor uses new.target to detect direct instantiation (new MnemopiPlugin(...)) and throws this TypeError immediately, because the base class carries no plugin behavior — subclasses must provide name and hook implementations.

Source

Thrown at packages/mnemopi/src/core/plugins.ts:19

import { existsSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";

export const DEFAULT_PLUGIN_DIR = join(homedir(), ".hermes", "mnemopi", "plugins");

export type PluginConfig = Record<string, unknown>;
export type MemoryDict = Record<string, unknown>;

export class MnemopiPlugin {
	static readonly abstractBase = true;
	name = "";
	version = "1.0.0";
	enabled = true;
	protected initialized = false;
	readonly config: PluginConfig;

	constructor(config: PluginConfig = {}) {
		if (new.target === MnemopiPlugin) throw new TypeError("MnemopiPlugin is abstract");
		this.config = config;
		const ctor = this.constructor as typeof MnemopiPlugin;
		this.name =
			(ctor.prototype.name as string | undefined) ?? (ctor as unknown as { name?: string }).name ?? this.name;
		this.version = (ctor.prototype.version as string | undefined) ?? this.version;
		this.enabled = (ctor.prototype.enabled as boolean | undefined) ?? this.enabled;
	}

	initialize(): void {
		this.initialized = true;
	}

	shutdown(): void {
		this.initialized = false;
	}

	onRemember(_memory: MemoryDict): void {
		throw new TypeError("Plugin must implement onRemember");

View on GitHub (pinned to 9690622007)

Solutions

  1. Instantiate a concrete subclass (e.g. new LoggingPlugin(config), new MetricsPlugin(config)) or your own class extending MnemopiPlugin
  2. Create a subclass that overrides at least the hooks you need and set name/version on the subclass
  3. If using a registry/factory, check that the plugin name maps to a registered concrete class, not the base

Example fix

// before
const plugin = new MnemopiPlugin(config);
// after
class MyPlugin extends MnemopiPlugin { override name = "my"; override onRemember(m: MemoryDict): void { /* ... */ } }
const plugin = new MyPlugin(config);
Defensive patterns

Strategy: type-guard

Validate before calling

type PluginCtor = new (config?: PluginConfig) => MnemopiPlugin;
function instantiateConcrete(Ctor: PluginCtor, config?: PluginConfig): MnemopiPlugin {
  if (Ctor === MnemopiPlugin) throw new TypeError("Pass a concrete plugin subclass, not MnemopiPlugin");
  return new Ctor(config);
}

Type guard

function isConcretePluginClass(C: unknown): C is new (config?: PluginConfig) => MnemopiPlugin {
  return typeof C === "function" && C !== MnemopiPlugin && C.prototype instanceof MnemopiPlugin;
}

Try / catch

try {
  plugin = instantiate(pluginName, config);
} catch (err) {
  if (err instanceof TypeError && err.message === "MnemopiPlugin is abstract") {
    logger.error(`plugin name "${pluginName}" resolved to the abstract base; check registration`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling new MnemopiPlugin(config) directly, or a plugin factory/registry that instantiates classes from config strings and resolves to the base class (e.g. a misspelled or unregistered subclass name falling back to the base).

Common situations: Copy-pasting setup code that instantiates the base instead of LoggingPlugin/MetricsPlugin or a custom subclass; a dynamic plugin loader mapping a config name to the wrong class; migrating code that previously allowed the base class.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/b7c1236c1feea8e6. Report an issue: GitHub.