larksuite/cli · error

nil connection

Error message

nil connection

What it means

validateConnRemoteIP performs the post-dial SSRF check by inspecting the connection's remote address. It throws this error when the net.Conn handed to it is nil, meaning no connection object exists to validate. This is a defensive guard so the validator never dereferences a nil connection.

Source

Thrown at internal/validate/url.go:549

func dialConn(ctx context.Context, dialFn func(context.Context, string, string) (net.Conn, error), network, addr string) (net.Conn, error) {
	if dialFn != nil {
		return dialFn(ctx, network, addr)
	}
	var d net.Dialer
	return d.DialContext(ctx, network, addr)
}

func downloadTargetPolicyError(err error) error {
	return errs.NewSecurityPolicyError(
		errs.SubtypeAccessDenied,
		"blocked download target: %v",
		err,
	).WithCause(err)
}

func validateConnRemoteIP(conn net.Conn) error {
	if conn == nil {
		return fmt.Errorf("nil connection")
	}
	raddr := conn.RemoteAddr()
	if raddr == nil {
		return fmt.Errorf("missing remote address")
	}
	host, _, err := net.SplitHostPort(raddr.String())
	if err != nil {
		host = raddr.String()
	}
	ip := net.ParseIP(strings.Trim(host, "[]"))
	if ip == nil {
		return fmt.Errorf("invalid remote IP")
	}
	if isRestrictedDownloadIP(ip) {
		return fmt.Errorf("local/internal host is not allowed")
	}
	return nil
}

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Ensure the dial result is checked: if err != nil return err before validating the conn
  2. Never call validateConnRemoteIP with a conn from a failed dial
  3. If wrapping the dialer, propagate the dial error instead of continuing with a nil connection

Example fix

// before
conn, _ := dialer.DialContext(ctx, network, addr)
err := validateConnRemoteIP(conn) // nil conn
// after
conn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
    return nil, err
}
err = validateConnRemoteIP(conn)
Defensive patterns

Strategy: validation

Validate before calling

if conn == nil {
    return fmt.Errorf("dial failed: no connection returned")
}
if err := validateConnRemoteIP(conn); err != nil { return err }

Type guard

func dialAndValidate(ctx context.Context, d *net.Dialer, network, addr string) (net.Conn, error) {
    conn, err := d.DialContext(ctx, network, addr)
    if err != nil || conn == nil {
        return nil, fmt.Errorf("dial %s: %w", addr, err)
    }
    return conn, validateConnRemoteIP(conn)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "nil connection") {
    return fmt.Errorf("dialer returned no connection without an error — fix the custom dialer: %w", err)
}

Prevention

When it happens

Trigger: The dialing helper returns (nil, nil) or the caller ignores the dial error and passes the nil conn to validateConnRemoteIP — typically from an anonymous wrapper around the dial-and-validate sequence.

Common situations: Custom DialContext wrappers that swallow dial errors; refactored dial paths returning a nil conn with a nil error; test doubles returning no connection.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/16c2326bc4241848. Report an issue: GitHub.