projectdiscovery/nuclei · critical

dialers not initialized for %s

Error message

dialers not initialized for %s

What it means

The JavaScript protocol's event-data builder panicked because dialers are missing for the template execution's id. generateEventData looks up protocolstate.GetDialersWithId(request.options.Options.ExecutionId) and panics on nil before assembling the per-request event map — so this fires at result/event generation time, i.e., only after a JS request actually ran, not at template compile time.

Source

Thrown at pkg/protocols/javascript/js.go:727

		callback(event)
	} else if request.options.Interactsh != nil {
		event = &output.InternalWrappedEvent{InternalEvent: data, UsesInteractsh: true}
		request.options.Interactsh.RequestEvent(interactshURLs, &interactsh.RequestData{
			MakeResultFunc: request.MakeResultEvent,
			Event:          event,
			Operators:      request.CompiledOperators,
			MatchFunc:      request.Match,
			ExtractFunc:    request.Extract,
		})
	}
	return nil
}

// generateEventData generates event data for the request
func (request *Request) generateEventData(input *contextargs.Context, values map[string]interface{}, matched string) map[string]interface{} {
	dialers := protocolstate.GetDialersWithId(request.options.Options.ExecutionId)
	if dialers == nil {
		panic(fmt.Sprintf("dialers not initialized for %s", request.options.Options.ExecutionId))
	}

	data := make(map[string]interface{})
	maps.Copy(data, values)
	data["type"] = request.Type().String()
	data["request-pre-condition"] = beautifyJavascript(request.PreCondition)
	data["request"] = beautifyJavascript(request.Code)
	data["host"] = input.MetaInput.Input
	data["matched"] = matched
	data["template-path"] = request.options.TemplatePath
	data["template-id"] = request.options.TemplateID
	data["template-info"] = request.options.TemplateInfo
	if request.StopAtFirstMatch || request.options.StopAtFirstMatch {
		data["stop-at-first-match"] = true
	}
	// add ip address to data
	if input.MetaInput.CustomIP != "" {
		data["ip"] = input.MetaInput.CustomIP

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Run protocolstate.Init(options) with the exact ExecutionId before executing any code-protocol template.
  2. Route scans through the official runner so event generation always happens post-Init.
  3. Guard the SDK boundary with protocolstate.ShouldInit(id).
  4. When cloning ExecutorOptions per run, either reuse the initialized id or re-Init for the new id.

Example fix

// before
// SDK executes a code template; on first match/extract generateEventData panics

// after
if protocolstate.ShouldInit(opts.ExecutionId) {
    if err := protocolstate.Init(opts); err != nil { return err }
}
results, err := jsEngine.ExecuteWithResults(ctx, template, ...)
Defensive patterns

Strategy: validation

Validate before calling

if protocolstate.ShouldInit(opts.ExecutionId) {
    if err := protocolstate.Init(opts); err != nil { return err }
}
results, err := jsEngine.ExecuteWithResults(ctx, ...)

Try / catch

// pre-validate; recovering this panic mid-event would corrupt result emission.

Prevention

When it happens

Trigger: Executing a code-protocol template in a process where protocolstate.Init never registered dialers for the active ExecutionId; an execution id present in ExecutorOptions but different from the one used at Init; dialers deleted mid-run (policy rebuild deletes then re-inits, so a race window exists if Init is skipped).

Common situations: lib/nuclei integrations and custom harnesses that drive pkg/protocols/javascript directly; late-binding execution ids cloned from options after Init ran under a previous id.

Related errors


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