projectdiscovery/nuclei · critical

dialers with executionId {executionId} not found

Error message

dialers with executionId {executionId} not found

What it means

The LDAP library constructor panicked because dialers were not registered for the current execution id. ldap.go fetchers executionId via c.nj.ExecutionId() and looks up protocolstate.GetDialersWithId; a nil result panics before any connection is attempted (including the ldapi:// Unix-socket path). This is a JS runtime initialization defect, not an LDAP protocol error.

Source

Thrown at pkg/js/libs/ldap/ldap.go:95

	c.cfg = utils.GetStructTypeSafe[Config](c.nj, call.Arguments, 2, Config{})
	c.Realm = realm
	c.BaseDN = fmt.Sprintf("dc=%s", strings.Join(strings.Split(realm, "."), ",dc="))

	// validate arguments
	c.nj.Require(ldapUrl != "", "ldap url cannot be empty")
	c.nj.Require(realm != "", "realm cannot be empty")

	u, err := url.Parse(ldapUrl)
	c.nj.HandleError(err, "invalid ldap url supported schemas are ldap://, ldaps://, ldapi://, and cldap://")
	if u.Scheme == "" {
		// default to ldap
		u.Scheme = "ldap"
	}

	executionId := c.nj.ExecutionId()
	dialers := protocolstate.GetDialersWithId(executionId)
	if dialers == nil {
		panic("dialers with executionId " + executionId + " not found")
	}

	dialCtx := c.nj.Context()
	var conn net.Conn
	if u.Scheme == "ldapi" {
		// the ldapi unix domain socket is not covered by the IP-based network
		// policy directly, so gate it on whether loopback access is permitted
		// (blocked when local network access is restricted via -lna).
		const ldapiPolicyHost = "127.0.0.1"

		c.nj.Require(protocolstate.IsHostAllowed(executionId, ldapiPolicyHost), protocolstate.ErrHostDenied.Msgf(ldapiPolicyHost).Error())
		if u.Path == "" || u.Path == "/" {
			u.Path = "/var/run/slapd/ldapi"
		}
		conn, err = dialers.Fastdialer.Dial(dialCtx, "unix", u.Path)
		c.nj.HandleError(err, "failed to connect to ldap server")
	} else {
		switch u.Scheme {

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Ensure protocolstate.Init(options) with the matching Options.ExecutionId runs before any template executes.
  2. Drive templates through the official nuclei runner, which owns the Init lifecycle.
  3. Pre-check protocolstate.ShouldInit(executionId) in SDK code before instantiating engines.
  4. Keep the executionId injected into the JS context identical to the one used at Init.

Example fix

// before
err := engine.Execute(template, target) // LDAP template -> panic

// after
if protocolstate.ShouldInit(opts.ExecutionId) {
    if err := protocolstate.Init(opts); err != nil { return err }
}
err := engine.Execute(template, target)
Defensive patterns

Strategy: validation

Validate before calling

if protocolstate.ShouldInit(execID) {
    if err := protocolstate.Init(opts); err != nil { return err }
}
// now the LDAP lib's internal GetDialersWithId lookup succeeds

Try / catch

// no catch: panics in the JS runtime abort the template run; fix initialization order.

Prevention

When it happens

Trigger: A code-protocol template using the LDAP client (nuclei's goja LDAP bindings) inside a process where protocolstate.Init never registered dialers for that ExecutionId; ctx executionId not matching the id used at Init; running the JS LDAP lib in a custom harness without the standard runner.

Common situations: lib/nuclei embedders exercising LDAP templates; third-party runners that build the goja runtime themselves; versions where dialers moved from global to per-execution-id registration.

Related errors


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