{"record":{"id":"e3ba516de601683e","repo":"projectdiscovery/nuclei","slug":"could-not-compile-flow-s","errorCode":null,"errorMessage":"could not compile flow: %s","messagePattern":"could not compile flow: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tmplexec/exec.go","lineNumber":49,"sourceCode":"\tengine   TemplateEngine\n\tresults  *atomic.Bool\n\tprogram  *goja.Program\n}\n\n// Both executer & Executor are correct spellings (its open to interpretation)\n\nvar _ protocols.Executer = &TemplateExecuter{}\n\n// NewTemplateExecuter creates a new request TemplateExecuter for list of requests\nfunc NewTemplateExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) (*TemplateExecuter, error) {\n\te := &TemplateExecuter{requests: requests, options: options, results: &atomic.Bool{}}\n\tif options.Flow != \"\" {\n\t\t// we use a dummy input here because goal of flow executor at this point is to just check\n\t\t// syntax and other things are correct before proceeding to actual execution\n\t\t// during execution new instance of flow will be created as it is tightly coupled with lot of executor options\n\t\tp, err := compiler.SourceAutoMode(options.Flow, false)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not compile flow: %s\", err)\n\t\t}\n\t\te.program = p\n\t} else {\n\t\t// only use generic if there is only 1 protocol with only 1 section\n\t\tif len(requests) == 1 {\n\t\t\te.engine = generic.NewGenericEngine(requests, options, e.results)\n\t\t} else {\n\t\t\te.engine = multiproto.NewMultiProtocol(requests, options, e.results)\n\t\t}\n\t}\n\treturn e, nil\n}\n\n// Compile compiles the execution generators preparing any requests possible.\nfunc (e *TemplateExecuter) Compile() error {\n\tcliOptions := e.options.Options\n\n\tfor _, request := range e.requests {","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/tmplexec/exec.go#L31-L67","documentation":"In pkg/tmplexec/exec.go, NewTemplateExecuter compiles the template's `flow:` JavaScript program up front (compiler.SourceAutoMode with a dummy input) purely to validate it before execution begins. If the goja parser rejects the flow source, template compilation aborts with 'could not compile flow: <parser error>'. This is a fail-fast check: only syntax is validated here, not whether functions like http() exist at runtime.","triggerScenarios":"A template with a `flow:` key whose value has invalid JavaScript/ES syntax: unbalanced parentheses or braces (e.g. `flow: \"http() && (dns()\"`), unterminated strings, smart quotes pasted from docs, illegal characters, or using `if(...)` without braces around a block. Loading such a template via the catalog triggers the error immediately at NewTemplateExecuter, before any target is scanned.","commonSituations":"Hand-writing or editing flow templates; copy-pasting flow snippets from blog posts where quotes were converted to typographic quotes; refactoring a multi-protocol template into flow mode and leaving a stray brace; note the error occurs at load time so `-validate` reproduces it cheaply.","solutions":["Run `nuclei -validate -t your-template.yaml` to reproduce and see the exact parser position in the wrapped error message","Fix the JavaScript syntax in the `flow:` field (balance parens/braces/quotes, use straight quotes)","Compare against a known-good flow template (e.g. in nuclei-templates, flows/) for structural reference","Remember undefined variables/functions are NOT caught here — those fail later during execution, so after fixing syntax, smoke-test the flow on one host"],"exampleFix":"# before\nflow: |\n  http() && && dns()\n# error: could not compile flow: ...\n\n# after\nflow: |\n  http() && dns()","handlingStrategy":"validation","validationCode":"// Pre-validate flow syntax the same way NewTemplateExecuter does:\nimport \"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/compiler\"\n\nif tmpl.Info.Flow != \"\" { // or options.Flow\n    if _, err := compiler.SourceAutoMode(tmpl.Info.Flow, false); err != nil {\n        return fmt.Errorf(\"template %s has invalid flow: %w\", tmpl.ID, err)\n    }\n}","typeGuard":null,"tryCatchPattern":"executer, err := tmplexec.NewTemplateExecuter(requests, options)\nif err != nil {\n    if strings.Contains(err.Error(), \"could not compile flow\") {\n        // deterministic template defect — drop template, report to author\n        return fmt.Errorf(\"template rejected (flow syntax): %w\", err)\n    }\n    return err\n}","preventionTips":["Run `nuclei -validate -t template.yaml` in template CI before shipping flow templates","Author flow in an editor with JS syntax highlighting; use straight ASCII quotes","Keep flows minimal; a syntax error in one template blocks its whole load path"],"tags":["flow","javascript","template","syntax","validation"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}