projectdiscovery/nuclei · error

invalid address %q: %w

Error message

invalid address %q: %w

What it means

DialWithExec could not split the address into host and port because net.SplitHostPort failed. Every address handed to the execution-bound goimpacket dialer must be in host:port form; IPv6 literals must be bracketed. The malformed address is reported verbatim in the message.

Source

Thrown at pkg/js/libs/gptransport/dialer.go:48

// given executionId. Every connection made through the returned dialer is
// validated against the execution's network policy and routed through the
// matching fastdialer.
func NewExecDialer(execID string) *gptr.Dialer {
	if execID == "" {
		return &gptr.Dialer{}
	}
	return &gptr.Dialer{
		DialFn: func(ctx context.Context, network, address string) (net.Conn, error) {
			return DialWithExec(ctx, execID, network, address)
		},
	}
}

// DialWithExec performs the fastdialer dial after enforcing host policy.
func DialWithExec(ctx context.Context, execID, network, address string) (net.Conn, error) {
	host, _, err := net.SplitHostPort(address)
	if err != nil {
		return nil, fmt.Errorf("invalid address %q: %w", address, err)
	}
	if !protocolstate.IsHostAllowed(execID, host) {
		return nil, protocolstate.ErrHostDenied.Msgf(host)
	}
	dialer := protocolstate.GetDialersWithId(execID)
	if dialer == nil || dialer.Fastdialer == nil {
		return nil, fmt.Errorf("goimpacket: no fastdialer registered for executionId %q", execID)
	}
	return dialer.Fastdialer.Dial(ctx, network, address)
}

// ExecutionIDFromCtx pulls the executionId set by nuclei on its goja runtime
// or scan context. Returns "" when the context carries no id.
func ExecutionIDFromCtx(ctx context.Context) string {
	if ctx == nil {
		return ""
	}
	if v := ctx.Value("executionId"); v != nil {

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Always pass host:port, building it with net.JoinHostPort(host, "445")
  2. Bracket IPv6 literals before appending the port: '[::1]:445'
  3. Trim and reject empty addresses at config-parse time before any dial

Example fix

// before
conn, err := gptransport.DialWithExec(ctx, execID, "tcp", host)

// after: JoinHostPort is IPv6-safe and guarantees host:port
addr := net.JoinHostPort(strings.TrimSpace(host), "445")
conn, err := gptransport.DialWithExec(ctx, execID, "tcp", addr)
Defensive patterns

Strategy: validation

Validate before calling

if _, _, err := net.SplitHostPort(address); err != nil {
    address = net.JoinHostPort(host, port) // rebuild correctly before dialing
}
conn, err := gptransport.DialWithExec(ctx, execID, "tcp", address)

Type guard

func isDialableAddress(addr string) bool {
    _, _, err := net.SplitHostPort(addr)
    return err == nil
}

Try / catch

if err != nil && strings.HasPrefix(err.Error(), "invalid address") {
    // rebuild with net.JoinHostPort and retry once; otherwise surface the bad address

Prevention

When it happens

Trigger: Dialing with '127.0.0.1' or 'dc.acme.local' (no ':445' port suffix); IPv6 written as '::1:445' instead of '[::1]:445'; empty address string; address with stray whitespace or an extra colon.

Common situations: SMB/RPC libraries building targets as hostname-only strings; config storing host and port separately with a broken join; IPv6 targets from dual-stack scans; variables interpolated without trimming.

Related errors


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