crowdsecurity/crowdsec · error

labels not a map

Error message

labels not a map

What it means

After enabling, the 'labels' entry must be a map[string]any of label key/values to attach to events; the assertion parsedLabels["labels"].(map[string]any) failed, so the entity is rejected. This protects the source from malformed or flat label structures.

Source

Thrown at pkg/acquisition/modules/docker/source.go:108

	if !ok {
		d.logger.Errorf("%s has 'crowdsec.enable' label set but it's not a string", entityType)
		return nil, errors.New("crowdsec.enable not a string")
	}

	if strings.ToLower(enable) != "true" {
		d.logger.Debugf("%s has 'crowdsec.enable' label not set to true ignoring %s: %s", entityType, entityType, entityID)
		return nil, errors.New("crowdsec.enable not true")
	}

	if _, ok = parsedLabels["labels"]; !ok {
		d.logger.Errorf("%s has 'crowdsec.enable' label set to true but no 'labels' keys found", entityType)
		return nil, errors.New("no labels key")
	}

	labelsTypeCast, ok := parsedLabels["labels"].(map[string]any)
	if !ok {
		d.logger.Errorf("%s has 'crowdsec.enable' label set to true but 'labels' is not a map", entityType)
		return nil, errors.New("labels not a map")
	}

	d.logger.Debugf("%s labels %+v", entityType, labelsTypeCast)

	labels := make(map[string]string)

	for k, v := range labelsTypeCast {
		if v, ok := v.(string); ok {
			log.Debugf("label %s is a string with value %s", k, v)
			labels[k] = v
			continue
		}

		d.logger.Errorf("label %s is not a string", k)
	}

	return labels, nil
}

View on GitHub (pinned to 909b515798)

Solutions

  1. Express labels as key/value pairs under crowdsec.labels, e.g. crowdsec.labels.type=syslog and crowdsec.labels.program=ssh
  2. Never assign a scalar to crowdsec.labels itself — it must be a map
  3. If using compose, structure it as labels: { crowdsec: { enable: 'true', labels: { type: syslog } } } and verify nesting
  4. Dump the effective labels with 'docker inspect --format "{{json .Config.Labels}}"' to confirm the structure

Example fix

# before (scalar where a map is required)
labels:
  - crowdsec.enable=true
  - crowdsec.labels=syslog
# after (map of label key/values)
labels:
  - crowdsec.enable=true
  - crowdsec.labels.type=syslog
  - crowdsec.labels.program=sshd
Defensive patterns

Strategy: type-guard

Validate before calling

if strings.EqualFold(labels["crowdsec.enable"], "true") {
	for k, v := range labels {
		if strings.HasPrefix(k, "crowdsec.labels.") {
			_ = k + v // flat per-key labels are fine; a scalar crowdsec.labels is not
		}
	}
}

Type guard

func labelsIsMap(v any) bool {
	_, ok := v.(map[string]any)
	return ok
}

Try / catch

if _, err := source.EvalContainer(ctx, ctr); err != nil {
	if err.Error() == "labels not a map" {
		log.Errorf("container %s: crowdsec.labels must be key/value pairs, not a scalar", ctr.ID)
	}
}

Prevention

When it happens

Trigger: processCrowdsecLabels (via EvalContainer/EvalService) receives parsedLabels["labels"] as a non-map value — e.g. a string like crowdsec.labels=syslog, a list, or a bool — instead of a map of key/value pairs.

Common situations: User wrote crowdsec.labels as a single flat label with a scalar value instead of per-key labels (crowdsec.labels.type=...); a list under labels in YAML; tooling that flattens nested labels into one string.

Related errors


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