projectdiscovery/nuclei · error

panic occurred while executing flow: %v

Error message

panic occurred while executing flow: %v

What it means

A deferred recover inside FlowExecutor.Execute (pkg/tmplexec/flow/flow_executor.go:254, marked TODO for RCA) catches panics raised while the goja runtime executes the flow, logs them via ctx.LogError, and lets the scan continue. Notably the recover is skipped when running under CI (ci.IsCI()), so the same panic crashes the binary in CI — by design, to surface bugs there.

Source

Thrown at pkg/tmplexec/flow/flow_executor.go:254

	}()
	defer func() {
		// remove set builtin
		_ = runtime.GlobalObject().Delete("set")
		_ = runtime.GlobalObject().Delete("template")
		for proto := range f.protoFunctions {
			_ = runtime.GlobalObject().Delete(proto)
		}
		runtime.RemoveContextValue("executionId")
	}()

	// TODO(dwisiswant0): remove this once we get the RCA.
	defer func() {
		if ci.IsCI() {
			return
		}

		if r := recover(); r != nil {
			f.ctx.LogError(fmt.Errorf("panic occurred while executing flow: %v", r))
		}
	}()

	if ctx.OnResult == nil {
		return fmt.Errorf("output callback cannot be nil")
	}
	// before running register set of builtins
	if err := runtime.Set("set", func(call goja.FunctionCall) goja.Value {
		varName := call.Argument(0).Export()
		varValue := call.Argument(1).Export()
		f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Set(types.ToString(varName), varValue)
		return goja.Null()
	}); err != nil {
		return err
	}
	// also register functions that allow executing protocols from js
	for proto, fn := range f.protoFunctions {
		if err := runtime.Set(proto, fn); err != nil {

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Upgrade nuclei to the latest patch release — flow panic fixes land frequently
  2. Reduce the template to the smallest flow that still panics (drop protocol sections one by one) and re-run to isolate the trigger
  3. Run the repro in CI or with CI=true env to get a full goroutine dump instead of the recovered log line
  4. Report the issue to projectdiscovery/nuclei with the template YAML, nuclei -version, and the panic value from the log
Defensive patterns

Strategy: try-catch

Try / catch

// The engine already recovers outside CI; at the call site keep per-template isolation:
func runTemplateSafe(e protocols.Executer, ctx *scan.ScanContext) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered flow panic: %v", r)
        }
    }()
    return e.Execute(ctx)
}

Prevention

When it happens

Trigger: Any runtime panic inside flow execution: nil map or nil pointer dereference in a protocol callback, an unexpected type crossing the JS/Go boundary in the flow runtime, or a bug in the flow engine itself. It fires only on the non-CLI-interactive path where a template with `flow:` executes against a target and something panics mid-program.

Common situations: A flow template exercising an engine edge case (nil template ctx value, exotic extractor output fed back into flow); upgrading templates without upgrading nuclei; SDK reuse of a template executer across goroutines it wasn't built for.

Related errors


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