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

  1. Run `nuclei -validate -t your-template.yaml` to reproduce and see the exact parser position in the wrapped error message
  2. Fix the JavaScript syntax in the `flow:` field (balance parens/braces/quotes, use straight quotes)
  3. Compare against a known-good flow template (e.g. in nuclei-templates, flows/) for structural reference
  4. 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

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


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/e3ba516de601683e. Report an issue: GitHub.