m1k1o/neko · error

plugin '%s' not found

Error message

plugin '%s' not found

What it means

Returned by Manager.LookupService when no registered plugin matches pluginName (findPlugin on the dependency registry fails). LookupService exposes an exposable plugin's service; the lookup is purely by the name returned by plugin.Name().

Source

Thrown at server/internal/plugins/manager.go:151

		} else {
			manager.logger.Err(err).Msg("failed to start plugins, skipping...")
		}
	}
}

func (manager *ManagerCtx) Shutdown() error {
	_ = manager.plugins.forEach(func(d *dependency) error {
		err := d.plugin.Shutdown()
		manager.logger.Err(err).Str("plugin", d.plugin.Name()).Msg("plugin shutdown")
		return nil
	})
	return nil
}

func (manager *ManagerCtx) LookupService(pluginName string) (any, error) {
	plug, ok := manager.plugins.findPlugin(pluginName)
	if !ok {
		return nil, fmt.Errorf("plugin '%s' not found", pluginName)
	}

	expPlug, ok := plug.plugin.(types.ExposablePlugin)
	if !ok {
		return nil, fmt.Errorf("plugin '%s' is not exposable", pluginName)
	}

	return expPlug.ExposeService(), nil
}

func (manager *ManagerCtx) Metadata() []types.PluginMetadata {
	var plugins []types.PluginMetadata

	_ = manager.plugins.forEach(func(d *dependency) error {
		dependsOn := make([]string, 0)
		deps, isDependalbe := d.plugin.(types.DependablePlugin)
		if isDependalbe {
			dependsOn = deps.DependsOn()

View on GitHub (pinned to b0f01cedea)

Solutions

  1. Verify the exact plugin name (the value of plugin.Name()) and fix the LookupService argument
  2. Check startup logs for plugin load errors — if the plugin failed to load it will not be in the registry
  3. Ensure plugins are loaded and InitConfigs/Start completed before LookupService is called
  4. Guard the call site: treat the error as expected for optional plugins and fall back gracefully

Example fix

// before
svc, err := manager.LookupService("file_tranfer") // typo

// after
svc, err := manager.LookupService("filetransfer")
if err != nil {
    log.Warn().Err(err).Str("plugin", name).Msg("plugin service unavailable")
    return
}
Defensive patterns

Strategy: fallback

Validate before calling

// ensure plugin load phase completed and name exists before lookup
if len(manager.Plugins()) == 0 {
    return fmt.Errorf("plugins not loaded yet")
}
if _, ok := manager.plugins.findPlugin(name); !ok {
    return fmt.Errorf("unknown plugin %q; known: %v", name, knownNames())
}

Try / catch

svc, err := manager.LookupService(name)
if err != nil {
    if strings.Contains(err.Error(), "not found") {
        // optional plugin: degrade gracefully
        return nil, nil
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling LookupService(name) where name was never registered — typo in the name, the plugin failed to load/start earlier, or the plugin was removed (e.g. its deps entry deleted by the cycle-break in addPlugin).

Common situations: Typo'd plugin name in handler wiring; a plugin whose load failed at startup (see errors 67/68) so it never entered the registry; requesting a service before plugin load/init completed.

Related errors


AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01). Data as JSON: /api/errors/2e817618aa360b02. Report an issue: GitHub.