crowdsecurity/crowdsec · error

unable to build %s hook : %w

Error message

unable to build %s hook : %w

What it means

buildHookList compiles every hook of a stage via hook.Build (filter/apply expr compilation, apply-rule setup). If any hook fails to build, the stage build aborts and the underlying error is wrapped with the stage name (pre_eval, post_eval, on_match). This is a wrapper: look at the wrapped error (e.g. expr compile failure) for the root cause.

Source

Thrown at pkg/appsec/appsec.go:836

			wc.OutOfBandOptions.RequestBodyInMemoryLimit = wc.OutOfBand.Options.RequestBodyInMemoryLimit
		}

		wc.VariablesTracking = append(wc.VariablesTracking, wc.OutOfBand.VariablesTracking...)
		wc.OutOfBand.VariablesTracking = nil
	}
}

// buildHookList validates and compiles a list of hooks of the given stage.
func buildHookList(ctx context.Context, hooks []Hook, stage hookStage, patcher *appsecExprPatcher) ([]Hook, error) {
	var compiled []Hook

	for _, hook := range hooks {
		if hook.OnSuccess != "" && hook.OnSuccess != "continue" && hook.OnSuccess != "break" {
			return nil, fmt.Errorf("invalid 'on_success' for %s hook : %s", stage, hook.OnSuccess)
		}

		if err := hook.Build(ctx, stage, patcher); err != nil {
			return nil, fmt.Errorf("unable to build %s hook : %w", stage, err)
		}

		compiled = append(compiled, hook)
	}

	return compiled, nil
}

// buildPhaseHooks compiles pre_eval / post_eval / on_match hook lists into a
// PhaseHooks. phaseName is only used to wrap errors ("" for the shared section).
func buildPhaseHooks(ctx context.Context, phaseName string, pre, post, onMatch []Hook, patcher *appsecExprPatcher) (PhaseHooks, error) {
	var (
		out PhaseHooks
		err error
	)

	wrap := func(e error) error {
		if phaseName == "" || e == nil {

View on GitHub (pinned to 909b515798)

Solutions

  1. Look at the wrapped (%w) inner error for the real cause and fix it (usually an expr compile error)
  2. Note the stage prefix in the message to locate the failing phase section in the YAML
  3. Validate each hook's filter/apply expressions individually with the expr CLI or a small Go test
  4. Bisect by commenting out hooks in that stage until the build succeeds
Defensive patterns

Strategy: try-catch

Prevention

When it happens

Trigger: Build() → buildPhaseHooks → buildHookList where one hook's Build returns an error: invalid expr filter/apply (672/673), a referenced rule file that fails to load, or invalid hook options.

Common situations: An appsec rule with a bad expr filter; hook referencing a missing variable or rule; broken YAML that unmarshaled into a hook with empty/invalid fields that Build rejects.

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/ce8ff55f0a69635d. Report an issue: GitHub.