crowdsecurity/crowdsec · error

error compiling duration_expr of %s: %w

Error message

error compiling duration_expr of %s: %w

What it means

CrowdSec profiles support a `duration_expr` expression (expr language) that dynamically computes a ban duration per alert. At profile load time (NewProfile), each duration_expr is compiled with expr.Compile; if the expression is not valid expr syntax or references unknown fields/functions, compilation fails and NewProfile returns this wrapped error, aborting startup/configuration load.

Source

Thrown at pkg/csprofiles/csprofiles.go:69

		if runtime.Cfg.OnFailure != "" && runtime.Cfg.OnFailure != "continue" && runtime.Cfg.OnFailure != "break" && runtime.Cfg.OnFailure != "apply" {
			return nil, fmt.Errorf("invalid 'on_failure' for '%s' : %s", profile.Name, runtime.Cfg.OnFailure)
		}

		for fIdx, filter := range profile.Filters {
			if runtimeFilter, err = expr.Compile(filter, exprhelpers.GetExprOptions(map[string]interface{}{"Alert": &models.Alert{}})...); err != nil {
				return nil, fmt.Errorf("error compiling filter of '%s': %w", profile.Name, err)
			}

			runtime.RuntimeFilters[fIdx] = runtimeFilter
			if profile.Debug != nil && *profile.Debug {
				runtime.Logger.Logger.SetLevel(log.DebugLevel)
			}
		}

		if profile.DurationExpr != "" {
			if runtimeDurationExpr, err = expr.Compile(profile.DurationExpr, exprhelpers.GetExprOptions(map[string]interface{}{"Alert": &models.Alert{}})...); err != nil {
				return nil, fmt.Errorf("error compiling duration_expr of %s: %w", profile.Name, err)
			}

			runtime.RuntimeDurationExpr = runtimeDurationExpr
		}

		for _, decision := range profile.Decisions {
			if runtime.RuntimeDurationExpr == nil {
				var duration string
				if decision.Duration != nil {
					duration = *decision.Duration
				} else {
					runtime.Logger.Warningf("No duration specified for %s, using default duration %s", profile.Name, defaultDuration)
					duration = defaultDuration
				}

				if _, err := cstime.ParseDurationWithDays(duration); err != nil {
					return nil, fmt.Errorf("error parsing duration '%s' of %s: %w", duration, profile.Name, err)
				}

View on GitHub (pinned to 909b515798)

Solutions

  1. Read the wrapped inner error: it pinpoints the expr parse/type error and position in duration_expr.
  2. Test the expression standalone (cscli or an expr playground) against an Alert model before putting it in config.
  3. Verify any function used exists in pkg/exprhelpers registry.
  4. Simplify: if the duration is constant, use the static `duration` field instead of duration_expr.

Example fix

// before (profiles.yaml)
duration_expr: Alert.StartAt + '4h'
// after
duration_expr: "'4h'"  # or a valid expr yielding a string like '4h'
Defensive patterns

Strategy: validation

Validate before calling

if profile.DurationExpr != "" {
    if _, err := expr.Compile(profile.DurationExpr, exprhelpers.GetExprOptions(map[string]interface{}{"Alert": &models.Alert{}})...); err != nil {
        return fmt.Errorf("invalid duration_expr for %s: %w", profile.Name, err)
    }
}

Prevention

When it happens

Trigger: Calling NewProfile (directly or via getProfilesConfigs/New during config load) with a profile whose `duration_expr` contains invalid expr syntax, an unknown field (e.g. not under Alert), a typo'd function name, or wrong types that expr's type checker rejects.

Common situations: Hand-editing profiles.yaml and typo-ing the expression; copying a filter expression that returns a non-duration value; using a helper function not registered in exprhelpers; referencing a variable like `duration` that doesn't exist in the expression environment.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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