crowdsecurity/crowdsec · error

plugin %q: notifier not registered

Error message

plugin %q: notifier not registered

What it means

tryNotify checks that a registered gRPC client exists in notificationPluginByName before calling Notify; if missing or nil it returns "plugin %q: notifier not registered". Config exists, but the plugin binary client was never successfully registered (spawn/Configure failed) or was lost.

Source

Thrown at pkg/csplugin/broker.go:390

	return raw.(protobufs.NotifierServer), nil
}

func (pb *PluginBroker) tryNotify(ctx context.Context, pluginName, message string) error {
	// config guard
	pc, ok := pb.pluginConfigByName[pluginName]
	if !ok {
		return fmt.Errorf("plugin %q: config not found", pluginName)
	}

	timeout := pc.TimeOut
	ctxTimeout, cancel := context.WithTimeout(ctx, timeout)

	defer cancel()

	// plugin guard
	plugin, ok := pb.notificationPluginByName[pluginName]
	if !ok || plugin == nil {
		return fmt.Errorf("plugin %q: notifier not registered", pluginName)
	}

	_, err := plugin.Notify(
		ctxTimeout,
		&protobufs.Notification{
			Text: message,
			Name: pluginName,
		},
	)

	return err
}

func (pb *PluginBroker) pushNotificationsToPlugin(ctx context.Context, pluginName string, alerts []*models.Alert) error {
	logger := log.WithField("plugin", pluginName)

	logger.Debugf("pushing %d alerts to plugin", len(alerts))

View on GitHub (pinned to 909b515798)

Solutions

  1. Search startup logs for the registration failure of this plugin (e.g. 'while configuring').
  2. Restart crowdsec so loadPlugins re-spawns the plugin binary.
  3. Verify the binary exists, is executable, and matches crowdsec's protobuf API.
  4. Test the plugin manually: run it standalone and check it starts and accepts config.

Example fix

// before: plugin binary removed after install
$ ls plugins/  # notification-email missing
// after
make build && cp ./plugins/notification-email /usr/local/lib/crowdsec/plugins/ && systemctl restart crowdsec
Defensive patterns

Strategy: type-guard

Validate before calling

plugin, ok := broker.notificationPluginByName[name]
if !ok || plugin == nil { /* skip or reschedule */ }

Type guard

func isRegistered(m map[string]protobufs.PluginClient, name string) bool {
    p, ok := m[name]
    return ok && p != nil
}

Try / catch

if !isRegistered(broker.notificationPluginByName, name) {
    log.Warnf("notifier %s not registered; will retry on next alert", name)
    return nil
}

Prevention

When it happens

Trigger: tryNotify with a plugin that has a config but no registered client: binary failed to start earlier, Configure failed (805) but processing continued, or plugin process died and the client was removed.

Common situations: Plugin binary crashed after startup; startup error for this plugin was logged and crowdsec continued without it; plugin_dir changed between runs; partial Init failure tolerated in a caller that proceeds anyway.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/11f0e5e751ca05ed. Report an issue: GitHub.