crowdsecurity/crowdsec · error

crowdsec.enable not a string

Error message

crowdsec.enable not a string

What it means

Docker labels are always strings, but processCrowdsecLabels received a parsed 'enable' entry whose dynamic value is not a string, so the type assertion parsedLabels["enable"].(string) failed and the entity is rejected. This guard exists because labels may be re-parsed/normalized before validation.

Source

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

	return parseLabels(containerDetails.Container.Config.Labels)
}

func (d *Source) processCrowdsecLabels(parsedLabels map[string]any, entityID string, entityType string) (map[string]string, error) {
	if len(parsedLabels) == 0 {
		d.logger.Tracef("%s has no 'crowdsec' labels set, ignoring %s: %s", entityType, entityType, entityID)
		return nil, errors.New("no crowdsec labels")
	}

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

	enable, ok := parsedLabels["enable"].(string)
	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")
	}

View on GitHub (pinned to 909b515798)

Solutions

  1. Set the label as a plain string: crowdsec.enable=true (docker labels are strings; avoid structured config wrappers that coerce types)
  2. If using a custom label source, ensure values are serialized as strings before reaching the docker source
  3. Check for tooling or templates that emit YAML booleans and force quoting: crowdsec.enable: "true"
  4. Pin/verify crowdsec version; older parsers handled label types differently

Example fix

# before (values coerced to bool)
labels:
  crowdsec.enable: true
# after (string, as docker labels require)
labels:
  crowdsec.enable: "true"
Defensive patterns

Strategy: type-guard

Validate before calling

v, ok := labels["crowdsec.enable"]
if !ok || reflect.TypeOf(v) != reflect.TypeOf("") {
	return fmt.Errorf("crowdsec.enable must be a string, got %T", v)
}

Type guard

func enableIsString(v any) bool {
	_, ok := v.(string)
	return ok
}

Try / catch

if _, err := source.EvalContainer(ctx, ctr); err != nil {
	if strings.Contains(err.Error(), "crowdsec.enable not a string") {
		log.Errorf("container %s: quote the enable label value", ctr.ID)
	}
}

Prevention

When it happens

Trigger: processCrowdsecLabels (via EvalContainer/EvalService) sees parsedLabels["enable"] present but holding a non-string value (e.g. bool or number after custom parsing), failing the .(string) assertion.

Common situations: Users writing enable=true in a config layer that parses YAML/JSON types instead of raw docker labels; custom wrappers feeding non-string label maps; boolean-like values coerced upstream.

Related errors


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