crowdsecurity/crowdsec · error

cannote create %s reader: %w

Error message

cannote create %s reader: %w

What it means

Wraps any failure from Configuration.NewReader() while the kafka acquisition source is configured. NewReader can fail when both group_id and partition are set (mutually exclusive), or when kafka.ReaderConfig.Validate() rejects the combination. Note the typo 'cannote' in the message itself — searching logs for 'cannot create kafka reader' will miss it.

Source

Thrown at pkg/acquisition/modules/kafka/config.go:90

func (s *Source) Configure(_ context.Context, yamlConfig []byte, logger *log.Entry, metricsLevel metrics.AcquisitionMetricsLevel) error {
	s.logger = logger
	s.metricsLevel = metricsLevel

	s.logger.Debugf("start configuring %s source", s.GetName())

	err := s.UnmarshalConfig(yamlConfig)
	if err != nil {
		return err
	}

	dialer, err := s.Config.NewDialer()
	if err != nil {
		return fmt.Errorf("cannot create %s dialer: %w", s.GetName(), err)
	}

	s.Reader, err = s.Config.NewReader(dialer, s.logger)
	if err != nil {
		return fmt.Errorf("cannote create %s reader: %w", s.GetName(), err)
	}

	if s.Reader == nil {
		return fmt.Errorf("cannot create %s reader", s.GetName())
	}

	s.logger.Debugf("successfully configured %s source", s.GetName())

	return nil
}

func (c *Configuration) NewTLSConfig() (*tls.Config, error) {
	tlsConfig := tls.Config{
		InsecureSkipVerify: c.TLS.InsecureSkipVerify,
	}

	cert, err := tls.LoadX509KeyPair(c.TLS.ClientCert, c.TLS.ClientKey)
	if err != nil {

View on GitHub (pinned to 909b515798)

Solutions

  1. In the kafka acquisition yaml, keep only one of `group_id` or `partition` — they are mutually exclusive
  2. Remove the `partition:` key if you intend consumer-group semantics; partition mode also only reads a single partition
  3. Check the wrapped %w error in logs: 'cannot specify both group_id and partition' vs a Validate() message
  4. Read the yaml with strict parsing (CrowdSec already does) to confirm no unexpected keys cause a mis-parse

Example fix

// before
source: kafka
brokers: [broker:9092]
topic: crowdsec
group_id: crowdsec
partition: 1   # mutually exclusive
// after
source: kafka
brokers: [broker:9092]
topic: crowdsec
group_id: crowdsec
Defensive patterns

Strategy: validation

Validate before calling

if cfg.GroupID != "" && cfg.Partition != 0 {
    return errors.New("kafka: group_id and partition are mutually exclusive")
}

Try / catch

if err := src.Configure(ctx, yamlCfg, logger, lvl); err != nil {
    if strings.Contains(err.Error(), "both group_id and partition") {
        logger.Error("fix acquisition yaml: drop either group_id or partition")
    }
    return err
}

Prevention

When it happens

Trigger: Configure() calls Config.NewReader(dialer, logger) and it returns an error — specifically when a kafka acquisition yaml sets both `group_id` and a non-zero `partition`, or when kafka-go's ReaderConfig.Validate() fails (e.g. invalid Address/Group balancing config).

Common situations: Operator converts from partition-based to consumer-group consumption and forgets to remove `partition:`; kafka-go version where Validate() rejects some combination; copy-pasted config keeping a stale `partition: 1`.

Related errors


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