crowdsecurity/crowdsec · error

unable to run appsec %s filter %s : %w

Error message

unable to run appsec %s filter %s : %w

What it means

During hook evaluation (on_request/on_response/pre_eval), each rule's FilterExpr is an expr-lang expression executed with exprhelpers.Run. If evaluation itself errors (bad syntax compiled past validation, missing variable, wrong return type at runtime), this error wraps it and aborts the hook stage for the request.

Source

Thrown at pkg/appsec/appsec.go:1081

//
// state, when non-nil, is consulted between rule iterations: if
// state.HooksHalted is true (set by a terminal expr helper such as
// RejectSubmission or the on_challenge_submit GrantChallengeCookie),
// remaining rules in this phase are skipped. ProcessOnLoadRules passes
// nil — it has no request state at all.
func (w *AppsecRuntimeConfig) processHooks(hooks []Hook, env map[string]interface{}, hookType string, state *AppsecRequestState) error {
	has_match := false

	for _, rule := range hooks {
		if state != nil && state.HooksHalted {
			w.Logger.Debugf("hooks halted by a terminal action; skipping remaining %s rules", hookType)
			break
		}

		if rule.FilterExpr != nil {
			output, err := exprhelpers.Run(rule.FilterExpr, env, w.Logger, w.Logger.Level >= log.DebugLevel)
			if err != nil {
				return fmt.Errorf("unable to run appsec %s filter %s : %w", hookType, rule.Filter, err)
			}

			switch t := output.(type) {
			case bool:
				if !t {
					w.Logger.Debugf("filter didnt match")
					continue
				}
			default:
				w.Logger.Errorf("Filter must return a boolean, can't filter")
				continue
			}

			has_match = true
		}

		for _, applyExpr := range rule.ApplyExpr {
			o, err := exprhelpers.Run(applyExpr, env, w.Logger, w.Logger.Level >= log.DebugLevel)

View on GitHub (pinned to 909b515798)

Solutions

  1. Fix the filter expression in the hook config, verifying every variable against the appsec eval env (request, tx, etc.)
  2. Test the expression with `cscli explain` or a small expr snippet before deploying
  3. Check the wrapped error for the exact variable/operation that failed
  4. Upgrade crowdsec if the expression uses a newer env field added in a recent version

Example fix

// before (hook filter)
filter: request.url.contains('
// after
filter: request.url.Path != '' && request.Method == 'POST'
Defensive patterns

Strategy: try-catch

Validate before calling

expr, err := expr.Compile(filter, expr.Env(appsecEnv{}))
if err != nil {
    return fmt.Errorf("bad hook filter %q: %w", filter, err)
}

Try / catch

if _, err := exprhelpers.Run(rule.FilterExpr, env, logger, false); err != nil {
    logger.Errorf("hook filter %q failed: %v — fix or remove the rule", rule.Filter, err)
    return // or fall back to default allow/deny policy
}

Prevention

When it happens

Trigger: Rule filter referencing an undefined variable/function in the env; expression raising a runtime error (e.g. type error on nil map access); malformed expression that passed compile but fails at eval.

Common situations: Custom hook expression using a typo'd variable name; expression written against an older appsec env schema after an upgrade; filter accessing request fields absent for that request type.

Related errors


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