Skip to content
This repository has been archived by the owner on Aug 12, 2023. It is now read-only.

[null-ls] failed to run generator: ...site\pack\packer\start\null-ls.nvim/lua/null-ls/loop.lua:165: command eslint_d is not executable (make sure it's installed and on your $PATH) #1118

Closed
kul-sudo opened this issue Sep 18, 2022 · 12 comments · May be fixed by #1341

Comments

@kul-sudo
Copy link

kul-sudo commented Sep 18, 2022

Nvim version: v0.8.0-dev-1112-g6d557e324 #1118

[null-ls] failed to run generator: ...site\pack\packer\start\null-ls.nvim/lua/null-ls/loop.lua:165: command eslint_d is not executable (make sure it's installed and on your $PATH)

Every single time I go into a .jsx file of my NextJS project, I see this message. The linter does not work indeed.
I use the well-known Devaslife's config: https://github.com/craftzdog/dotfiles-public

image

eslint_d is in my environment variables:
image

@kul-sudo kul-sudo changed the title v0.8.0-dev-1112-g6d557e324 [null-ls] failed to run generator: ...site\pack\packer\start\null-ls.nvim/lua/null-ls/loop.lua:165: command eslint_d is not executable (make sure it's installed and on your $PATH) Sep 18, 2022
@jose-elias-alvarez
Copy link
Owner

jose-elias-alvarez commented Sep 18, 2022

Please do not delete the issue template - without that information there is nothing I can do about this. In addition to that, what does Neovim output when you run :echo exepath("eslint_d")?

@kul-sudo
Copy link
Author

Please do not delete the issue template - without that information there is nothing I can do about this. In addition to that, what does Neovim output when you run :echo exepath("eslint_d")?

C:\Users\User\AppData\Roaming\npm\eslint_d

@jose-elias-alvarez jose-elias-alvarez closed this as not planned Won't fix, can't repro, duplicate, stale Sep 19, 2022
@YangShaoyue
Copy link

YangShaoyue commented Jan 10, 2023

Hi, I just encountered this issue and solved it with :MasonInstall eslint_d.

Yesterday, I installed eslint with npm i eslint -g and everything was OK, it linted well in my frontend project, but today when I reopened that project, eslint was not working.
I changed eslint to eslint_d and installed it with npm as well npm i -g eslint_d, but it had the same issue too. Until I installed eslint_d using Mason in Neovim.

It's very weird still, eslint and eslint_d both are executable globally in PowerShell, and in Neovim the output of :echo exepath("eslint_d") is C:\Users\ysy\AppData\Roaming\npm\eslint_d, seems everything is OK.

Maybe it is null-ls's bug? @jose-elias-alvarez

Platform Info

System: Windows 11
Neovim version:
图片

@jose-elias-alvarez
Copy link
Owner

jose-elias-alvarez commented Jan 10, 2023

If it is a bug on our end, then it's a bug with the mechanism we use to spawn processes, in which case there's very little we can do about it. I believe this is somehow related to Node executables on Windows, but learning more will require deep investigation, and I don't have a Windows development environment to test this out for myself (and it also seems to be working without problems for most users).

@YangShaoyue
Copy link

I think I find the reason, maybe null-ls can choose linter executable path according to system platform? I'm not familiar with Lua, it's just a guess.

Here is my investigation:
A few hours ago, I installed stylelint using npm i --save-dev stylelint (and also npm i -g stylelint) for my frontend project, when I opened a .scss file, the same problem came out, just like this eslint issue.

[WARN  2023/1/11 21:00:28] ...ack\packer\start\null-ls.nvim/lua/null-ls/generators.lua:94: failed to run generator: ...site\pack\packer\start\null-ls.nvim/lua/null-ls/loop.lua:154: F:\Workspace\medical-insurance\node_modules\.bin\stylelint
[TRACE 2023/1/11 21:04:12] ...te\pack\packer\start\null-ls.nvim/lua/null-ls/client.lua:97: starting null-ls client
[TRACE 2023/1/11 21:04:12] ...\site\pack\packer\start\null-ls.nvim/lua/null-ls/rpc.lua:102: received LSP request for method initialize
[TRACE 2023/1/11 21:04:12] ...\site\pack\packer\start\null-ls.nvim/lua/null-ls/rpc.lua:127: received LSP notification for method initialized
[TRACE 2023/1/11 21:04:12] ...\site\pack\packer\start\null-ls.nvim/lua/null-ls/rpc.lua:127: received LSP notification for method textDocument/didOpen
[TRACE 2023/1/11 21:04:12] ...ack\packer\start\null-ls.nvim/lua/null-ls/generators.lua:21: running generators for method NULL_LS_DIAGNOSTICS_ON_OPEN
[DEBUG 2023/1/11 21:04:12] ...t\null-ls.nvim/lua/null-ls/helpers/generator_factory.lua:320: spawning command "F:\\Workspace\\medical-insurance\\node_modules\\.bin\\stylelint" at F:\Workspace\medical-insurance with args { "--formatter", "json", "--stdin-filename", "F:\\Workspace\\medical-insurance\\packages\\renderer\\report.scss" }
[WARN  2023/1/11 21:04:12] ...ack\packer\start\null-ls.nvim/lua/null-ls/generators.lua:94: failed to run generator: ...site\pack\packer\start\null-ls.nvim/lua/null-ls/loop.lua:165: command F:\Workspace\medical-insurance\node_modules\.bin\stylelint is not executable (make sure it's installed and on your $PATH)

In F:\Workspace\medical-insurance\node_modules\.bin, there are 3 executable stylelint files:

  • stylelint (which is a sh script actually)
    图片
  • stylelint.cmd (this file content is omitted because it is not important for current issue)
  • stylelint.ps1 (this file content is omitted because it is not important for current issue)

Obviously in Windows platform sh script cannot be executed directly (the other two scripts .cmd and .ps1 can be executed directly), so null-ls fails to execute linter in this situation. When I delete F:\Workspace\medical-insurance\node_modules\.bin\stylelint, the problem is gone.

I checked out corresponding files according to trace stack, maybe dynamic_command function is relevant to this issue? but I'm totally new to Lua and not able to go deeper so far.

Hope this helps.

@jose-elias-alvarez
Copy link
Owner

Definitely helpful, thanks for looking into this. I had thought that exepath() took care of this on Windows - we use it here, and this nvim-lspconfig issue seems to indicate that that's the right solution. What is the output from this command?

:exepath("F:\Workspace\medical-insurance\node_modules\.bin\stylelint")

@YangShaoyue
Copy link

YangShaoyue commented Jan 12, 2023

I often switch programming computer between my personal computer and working computer, the frontend project path and Node.js path are not identical. So I want to use [..] to represent different path in case of various paths make you confusing. Those two computers both are in Windows 11 platform.

  • [NPM_PATH] means NPM installation path
  • [PROJECT_PATH] means frontend project path
  • [~] means Windows system local path which is C:\Users\[username]

Is there :exepath(......) command in Neovim? I think you mean :echo exepath(......).
Maybe eslint_d could expose more debugging info because it can be installed with NPM (globally and locally) and Mason, I can not find eslint and stylelint in Mason Linter. Here are various outputs in different situations:

Situation 1

  • installed as project devDependency npm i --save-dev eslint_d
  • installed globally npm i -g eslint_d
  • installed with Mason :MasonInstall eslint_d
    :echo exepath("eslint_d") outputs nothing
    :echo exepath("[PROJECT_PATH]\node_modules\.bin\eslint_d") outputs nothing

In this situation, this issue comes out when I open a .js or .jsx file.

Situation 2

  • installed as project devDependency npm i --save-dev eslint_d
  • installed globally npm i -g eslint_d
  • installed with Mason :MasonInstall eslint_d
    :echo exepath("eslint_d") outputs [NPM_PATH]\eslint_d
    :echo exepath("[NPM_PATH]\eslint_d") outputs nothing
    :echo exepath("[PROJECT_PATH]\node_modules\.bin\eslint_d") outputs nothing

In this situation, this issue comes out too when I open a .js or .jsx file

Situation 3

  • installed as project devDependency npm i --save-dev eslint_d
  • installed globally npm i -g eslint_d
  • installed with Mason :MasonInstall eslint_d
    :echo exepath("eslint_d") outputs [~]\AppData\Local\nvim-data\mason\bin\eslint_d.CMD
    :echo exepath("[~]\AppData\Local\nvim-data\mason\bin\eslint_d.CMD") outputs nothing

In this situation, this issue disappeares when I open a .js or .jsx file, eslint_d runs well.

Situation 4

But, after Situation 3, in Neovim Mason when I uninstall eslint_d, eslint_d runs well still in frontend project, the output is the same as Situation 3, until I delete [~]\AppData\Local\nvim-data\mason\bin\eslint_d.CMD manually (this file is still there even though eslint_d is uninstalled).
Then I reinstalled eslint_d in Neovim Mason, the weird thing came out, eslint_d was not working any more.
The output of :echo exepath("eslint_d") is [~]\AppData\Local\nvim-data\mason\bin\eslint_d.CMD.

:NullLsLog info is:
[WARN 1/12/2023 12:10:48 PM] ...ack\packer\start\null-ls.nvim/lua/null-ls/generators.lua:94: failed to run generator: ...site\pack\packer\start\null-ls.nvim/lua/null-ls/loop.lua:165: command [PROJECT_PATH]\node_modules\.bin\eslint_d is not executable (make sure it's installed and on your $PATH), indicated Mason eslint_d was not used.

I checked related files in ...\nvim-data\mason and seemed that every file was exactly the same as Situation 3.

Maybe there are some other reasons and I'm working on solving the problem in Situation 4.

Update

For Situation 4, after I uninstalled eslint_d locally in my frontend project npm uninstall eslint_d, linter runs well again and output of :echo exepath("eslint_d") is [~]\AppData\Local\nvim-data\mason\bin\eslint_d.CMD.

@jose-elias-alvarez
Copy link
Owner

Is there :exepath(......) command in Neovim? I think you mean :echo exepath(......).

Haha, yes, sorry, too much time spent in Lua. Thanks for the thorough investigation! I'm actually not sure how Mason is interacting with things here, but I did think of a potential issue with null-ls core:

For most Node-based sources, we use this logic to determine whether a local executable is present. When combined with this wrapper, it means that if you're using the eslint_d source, null-ls will first look for $PROJECT/node_modules/.bin/eslint_d, then fall back to eslint_d (which will resolve from $PATH). Both of those will be passed into exepath(), which I assumed would "fix" the path to the executable on Windows as needed, but it seems like that's not the case.

If the issue is that null-ls is pointing at a shell script that Windows can't execute, and if the issue is specific to Node-based sources, then this patch may help. Could you give it a shot and let me know!

diff --git a/lua/null-ls/helpers/command_resolver.lua b/lua/null-ls/helpers/command_resolver.lua
index 66af8df..30942a0 100644
--- a/lua/null-ls/helpers/command_resolver.lua
+++ b/lua/null-ls/helpers/command_resolver.lua
@@ -1,6 +1,8 @@
 local cache = require("null-ls.helpers.cache")
 local u = require("null-ls.utils")
 
+local is_windows = vim.loop.os_uname().version:match("Windows")
+
 local M = {}
 
 --- search for a local executable and its parent directory from start_path to end_path
@@ -46,7 +48,11 @@ end
 M.from_node_modules = function()
     local node_modules_resolver = M.generic(u.path.join("node_modules", ".bin"))
     return function(params)
-        return node_modules_resolver(params) or params.command
+        local resolved_command = node_modules_resolver(params)
+        if resolved_command and is_windows then
+            resolved_command = u.path.join(resolved_command, ".cmd")
+        end
+        return resolved_command or params.command
     end
 end
 

@YangShaoyue
Copy link

Yes, this patch solved current issue.

And this line

resolved_command = u.path.join(resolved_command, ".cmd")

should actually be

resolved_command = resolved_command .. ".cmd"

or resolved_command value will be ...\node_modules\.bin\eslint\.cmd.

In addition, under this patch, :echo exepath("eslint") outputs nothing

@jose-elias-alvarez
Copy link
Owner

Ah, yeah, my bad. Is there any documentation about how npm creates these scripts in node_modules/.bin? If this is the documented Windows behavior, then I think the solution in the patch is fine.

@YangShaoyue
Copy link

I've been looking for that documentation after I tried this patch. I'm not very familiar with npm executable script creation mechanism. I will let you know if I find it.

@IronLu233
Copy link

Hi, @jose-elias-alvarez I found how does npm determine the executable file.

https://github.com/npm/libnpmexec/blob/e1378fc8b8e2243765b068d8eb45aba7d01d45bd/lib/index.js#L38

const exec = async (opts) => {
  const {
    args = [],
    call = '',
    color = false,
    localBin = resolve('./node_modules/.bin'),
    locationMsg = undefined,
    globalBin = '',
    output,
    packages: _packages = [],
    path = '.',
    runPath = '.',
    scriptShell = isWindows ? process.env.ComSpec || 'cmd' : 'sh',
    yes = undefined,
    ...flatOptions
  } = opts

So the patch is correct. I create a new PR for it. #1341

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants