projectdiscovery/nuclei · error
could not compile flow: %s
Error message
could not compile flow: %s
What it means
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.
Source
Thrown at pkg/tmplexec/exec.go:49
engine TemplateEngine
results *atomic.Bool
program *goja.Program
}
// Both executer & Executor are correct spellings (its open to interpretation)
var _ protocols.Executer = &TemplateExecuter{}
// NewTemplateExecuter creates a new request TemplateExecuter for list of requests
func NewTemplateExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) (*TemplateExecuter, error) {
e := &TemplateExecuter{requests: requests, options: options, results: &atomic.Bool{}}
if options.Flow != "" {
// we use a dummy input here because goal of flow executor at this point is to just check
// syntax and other things are correct before proceeding to actual execution
// during execution new instance of flow will be created as it is tightly coupled with lot of executor options
p, err := compiler.SourceAutoMode(options.Flow, false)
if err != nil {
return nil, fmt.Errorf("could not compile flow: %s", err)
}
e.program = p
} else {
// only use generic if there is only 1 protocol with only 1 section
if len(requests) == 1 {
e.engine = generic.NewGenericEngine(requests, options, e.results)
} else {
e.engine = multiproto.NewMultiProtocol(requests, options, e.results)
}
}
return e, nil
}
// Compile compiles the execution generators preparing any requests possible.
func (e *TemplateExecuter) Compile() error {
cliOptions := e.options.Options
for _, request := range e.requests {View on GitHub (pinned to 265b3a3dec)
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
Example fix
# before flow: | http() && && dns() # error: could not compile flow: ... # after flow: | http() && dns()
Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate flow syntax the same way NewTemplateExecuter does:
import "github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/compiler"
if tmpl.Info.Flow != "" { // or options.Flow
if _, err := compiler.SourceAutoMode(tmpl.Info.Flow, false); err != nil {
return fmt.Errorf("template %s has invalid flow: %w", tmpl.ID, err)
}
} Try / catch
executer, err := tmplexec.NewTemplateExecuter(requests, options)
if err != nil {
if strings.Contains(err.Error(), "could not compile flow") {
// deterministic template defect — drop template, report to author
return fmt.Errorf("template rejected (flow syntax): %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid request type %s
- validation failed for these fields
- Invalid severity: %s
- Invalid extractor type: %s
- Invalid matcher type: %s
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/e3ba516de601683e.
Report an issue: GitHub.