immich-app/immich · error
Unable to instantiate plugin
Error message
Unable to instantiate plugin: ${key} What it means
When loading a plugin, a worker pool is created and awaited via pool.ready(); if the worker fails to initialize (bad code, syntax error, missing dependency inside the plugin, initialization timeout), load() throws 'Unable to instantiate plugin: <key>' with the cause attached. The plugin is not registered in pluginMap and cannot be called.
Solutions
- Inspect the `cause` for the worker's real initialization error (stack trace from the plugin)
- Run/compile the plugin standalone to reproduce the init failure
- Install missing plugin dependencies and rebuild the plugin for the correct runtime/module format
- Fix any top-level throwing code in the plugin entry point
Example fix
// before (plugin/src/index.ts)
const cfg = JSON.parse(process.env.PLUGIN_CFG); // throws at init
// after
const cfg = process.env.PLUGIN_CFG ? JSON.parse(process.env.PLUGIN_CFG) : {}; Defensive patterns
Strategy: try-catch
Validate before calling
// before load(): smoke-check the plugin module compiles/loads await import(pluginPath); // throws early with the real syntax/resolve error
Try / catch
try {
await pluginRepo.load({ key, label /* ... */ });
} catch (e) {
if (String(e.message).startsWith('Unable to instantiate plugin')) {
logger.error(`Plugin ${key} failed to init`, { cause: (e as any).cause });
disabledPlugins.add(key); // continue startup without the plugin
} else throw e;
} Prevention
- Test plugin workers in CI with the same runtime version as production
- Install plugin dependencies inside the plugin's own environment
- Avoid throwing top-level code in plugin entry points; defer to explicit init()
- Validate the plugin manifest (key, entry path, module format) before load
When it happens
Trigger: load(key, path/label) creates a worker pool and pool.ready() rejects or times out — plugin source has a compile/syntax error, throws during top-level init, or a required module inside the plugin is missing.
Common situations: Plugin built for a different runtime version; plugin's dependencies not installed in the worker environment; top-level code throwing (bad config read); ESM/CJS module format mismatch; worker resource limits.
Related errors
- Plugin method call failed
- authToken is required
- Hostname did not match any listed in methods[].allowedHosts…
- Invalid token
- Invalid token: missing userId
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/b002e18b3e076e2c.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/repositories/plugin.repository.ts:240
info: (message) => logger.log(message),
debug: (message) => logger.debug(message),
warn: (message) => logger.warn(message),
error: (message) => logger.error(message),
} as Console,
logLevel: asExtismLogLevel(logger.getLogLevel()),
enableWasiOutput: true,
},
),
destroy: (plugin) => plugin.close(),
},
{ min: 1, max: 5 },
);
try {
await pool.ready();
this.pluginMap.set(key, { pool, label });
} catch (error: Error | any) {
throw new Error(`Unable to instantiate plugin: ${key}`, { cause: error });
}
}
async callMethod<T>({ pluginKey, methodName }: PluginMethod, input: unknown, context?: unknown) {
const item = this.pluginMap.get(pluginKey);
if (!item) {
throw new Error(`No loaded plugin found for ${pluginKey}`);
}
const { pool, label } = item;
try {
const plugin = await pool.acquire();
try {
const result = await plugin.call(methodName, JSON.stringify(input), context);
return (result ? result.json() : result) as T;
} finally {
await pool.release(plugin);View on GitHub (pinned to e55ac299a4)