{"record":{"id":"1c8c65ff4411ff5e","repo":"crowdsecurity/crowdsec","slug":"non-empty-filter-q-was-not-compiled","errorCode":null,"errorMessage":"non-empty filter %q was not compiled","messagePattern":"non-empty filter %q was not compiled","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/parser/node.go","lineNumber":80,"sourceCode":"\t\tchild := Node{NodeConfig: subNodes[i]}\n\t\tchild.initRuntimeChildrenFromConfig()\n\t\tn.LeavesNodes[i] = child\n\t}\n}\n\nfunc (n *Node) validate(ectx EnricherCtx) error {\n\t// stage is being set automagically\n\tif n.Stage == \"\" {\n\t\treturn errors.New(\"stage needs to be an existing stage\")\n\t}\n\n\t/* \"\" behaves like continue */\n\tif n.OnSuccess != \"continue\" && n.OnSuccess != \"next_stage\" && n.OnSuccess != \"\" {\n\t\treturn fmt.Errorf(\"onsuccess %q not continue,next_stage\", n.OnSuccess)\n\t}\n\n\tif n.Filter != \"\" && n.RunTimeFilter == nil {\n\t\treturn fmt.Errorf(\"non-empty filter %q was not compiled\", n.Filter)\n\t}\n\n\tif n.RuntimeGrok.RunTimeRegexp != nil || n.Grok.TargetField != \"\" {\n\t\tif err := n.Grok.Validate(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfor idx, static := range n.Statics {\n\t\tif err := static.Validate(ectx); err != nil {\n\t\t\treturn fmt.Errorf(\"static %d: %w\", idx, err)\n\t\t}\n\t}\n\n\tfor idx, stash := range n.Stashes {\n\t\tif err := stash.Validate(); err != nil {\n\t\t\treturn fmt.Errorf(\"stash %d: %w\", idx, err)\n\t\t}","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/parser/node.go#L62-L98","documentation":"Node.validate() enforces that any node with a non-empty Filter has already had that expression compiled into RunTimeFilter. If Filter is set but RunTimeFilter is nil, the compile step was skipped or failed silently, so validation rejects the node to prevent runtime evaluation of an uncompiled expression.","triggerScenarios":"validate() sees n.Filter != \"\" while n.RunTimeFilter == nil — the filter expression was never compiled (e.g. compile step bypassed, or filter present but compilation returned nil on some path).","commonSituations":"Programmatically constructed nodes (or test harnesses) that set Filter without calling the expression compilation step; config plumbing bugs where compile() wasn't invoked before validate().","solutions":["Ensure node.Compile()/the compilation stage runs before validate(); fix the calling order in the loader.","If constructing nodes in code or tests, explicitly compile the filter expression with exprhelpers options before validating.","If the filter failed to compile earlier, fix the underlying expression error surfaced by the compile step."],"exampleFix":"// before\nnode := &Node{Filter: \"evt.Parsed.x == '1'\"}\nnode.Validate()\n// after\nnode := &Node{Filter: \"evt.Parsed.x == '1'\"}\nif err := node.Compile(pctx); err != nil { return err }\nif err := node.Validate(ectx); err != nil { return err }","handlingStrategy":"type-guard","validationCode":"if node.Filter != \"\" && node.RunTimeFilter == nil {\n    // compile before validating\n    if err := node.Compile(pctx); err != nil { return err }\n}","typeGuard":"func filterCompiled(n *parsers.Node) bool {\n    return n.Filter == \"\" || n.RunTimeFilter != nil\n}","tryCatchPattern":"if !filterCompiled(node) {\n    if err := node.Compile(pctx); err != nil { return err }\n}\nif err := node.Validate(ectx); err != nil { return err }","preventionTips":["Always route node construction through the loader's compile stage before validation.","In tests/harnesses, call Compile() before Validate() on hand-built nodes.","Never set Filter directly on a node after compilation."],"tags":["parser","validation","expr","crowdsec"],"backgroundTag":"internal-invariant-violation","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}