sublimelsp / LSP

Client implementation of the Language Server Protocol for Sublime Text
https://lsp.sublimetext.io/
MIT License
1.65k stars 183 forks source link

Could not start LSP-* due to not being able to find Node.js runtime on the PATH #1671

Closed predragnikolic closed 2 years ago

predragnikolic commented 3 years ago

This is just a guide on how to handle this issue.

If you get a popup saying: Could not start LSP-* due to not being able to find Node.js runtime on the PATH. Press the "Install Node.js" button to install Node.js automatically (note that it will be installed locally for LSP and will not affect your system otherwise).

Depending if you already have Node.js installed on your system the fix is the following:

You don't have node installed on your system.

a) Press the Install Node.js button and LSP will automatically install the Node Runtime locally(Node V12 will be installed at the time of writing). It won't install Node globally!

b) You manually download and install Node.js. Keep in mind that there are some servers that don't work with specific versions of Node. (an error message will be printed in ST console(ctrl+`) if that is the case. For example LSP-intelephense: Error: Ignoring system Node.js runtime due to an error. Node.js version requirement failed. Expected minimum: 10.0.0, got 8.17.0.)

You have Node install on your system.

If you still see this popup "Could not start LSP-* due to not being able to find Node.js runtime on the PATH" but you have Node in your $PATH, that means that Sublime Text didn't pick up your $PATH. See https://lsp.sublimetext.io/troubleshooting/#updating-the-path-used-by-lsp-servers on how to resolve this.

Feel free to make suggestions to improve this guide. :)

niksy commented 3 years ago

I’m trying to manually set PATH with settings but this seems to not be working. Similar configuration (where I manually adjust PATH) works for SublimeLinter.

Node path is not available on PATH by default (I’m running different Node versions with nvm so I manually switch them in every shell). It works when I start from terminal with added Node path.

{
    "clients": {
        "LSP-typescript": {
            "env": {
                "PATH": "~/.nvm/current/bin:$PATH"
            }
        }
    }
}
rchl commented 3 years ago

Why don't you just follow setup mentioned in the guide? It even mentions the nvm case.

niksy commented 3 years ago

I was following explanation for nvm but it didn’t work.

If I set that path explicitly in .bash_profile in export PATH="..." statement and open editor from terminal, binary folder is correctly picked up and Node executable is recognized.

If I remove it from PATH in .bash_profile and add it to JSON configuration which I wrote in comment, Node executable is not picked up.

I want to avoid adding Node on every shell startup, so adding it through JSON configuration is excellent choice. I was under the impression that this will be used as PATH for that particular LSP implementation. For example, this is how it works for SublimeLinter configuration:

{
    "linters": {
        "eslint": {
            "selector": "text.html.svelte, text.html.vue, source.js - meta.attribute-with-value",
            "env": {
                "PATH": "~/.nvm/current/bin:$PATH"
            }
        },
        "stylelint": {
            "env": {
                "PATH": "~/.nvm/current/bin:$PATH"
            }
        },
        "shellcheck": {
            "selector": "source.shell"
        }
    }
}
rchl commented 3 years ago

Try this but in LSP-typescript settings (Preferences: LSP-typescript settings from the Command Palette).

{
    "env": {
        "PATH": "~/.nvm/current/bin"
    }
}
rchl commented 3 years ago

I'd still recommend doing as the documentation explains and make nvm init script run from .bash_profile or .zprofile. Then you don't need to customize all those settings and you have universal solution that works across all ST packages.

Note that modifying .bash_profile requires re-login for the changes to be picked up (on Linux at least).

niksy commented 3 years ago

Try this but in LSP-typescript settings (Preferences: LSP-typescript settings from the Command Palette). …

I did that already and it doesn’t work. So basically what this should do is append/prepend env.PATH to current Sublime PATH (probably sourced from .bash_profile), but without changing it globally (reffering to the comment)? What’s the best way to debug this so I can see what’s the final PATH used to locate Node executable? Also, I’m on macOS so maybe that should also count, but it’s *nix system in the way that these basic shell things should work (I guess).

I'd still recommend doing as the documentation explains and make nvm init script run from .bash_profile or .zprofile. Then you don't need to customize all those settings and you have universal solution that works across all ST packages.

Note that modifying .bash_profile requires re-login for the changes to be picked up (on Linux at least).

This is exactly what I’m trying to avoid, so I was expecting it to work just like with SublimeLinter when setting environment with settings. I mentioned that in previous comment.

rchl commented 3 years ago

OK, I've tried that and indeed that doesn't work. That's because we try to install the node dependencies before starting the sever and that already requires node to be in the PATH (or a LSP-local one to be used).

I guess if we would want to address that case then the fix would have to be in the https://github.com/sublimelsp/lsp_utils and it would need to allow specifying your own path to the node runtime.

niksy commented 3 years ago

OK, I've tried that and indeed that doesn't work. That's because we try to install the node dependencies before starting the sever and that already requires node to be in the PATH (or a LSP-local one to be used).

OK, so I guess I’m not crazy 😅

It isn’t possible to first modify PATH and then try to install depenndencies?

I guess if we would want to address that case then the fix would have to be in the sublimelsp/lsp_utils and it would need to allow specifying your own path to the node runtime.

So I guess this will be new option for nodejs_runtime option, or if it’s not system or local, just use value verbatim and assume that’s the path where node and npm are located?

Or maybe add support for env.PATH to lsp_utils.sublime-settings so it’s aligned with other implementations, and count for the value of env.PATH when resolving system value for nodejs_runtime? This means updating global PATH though since system lookup expectes that Node and npm are available in PATH.

AmjadHD commented 3 years ago

What's the best way for now to not loose the server ? stop package control from upgrading the plugin (lsp-pyright, ...) ?

jwortmann commented 3 years ago

What's the best way for now to not loose the server, stop package control from upgrading the plugin (lsp-pyright, ...) ?

Package Control has this setting (in Package Control.sublime-settings):

{
    // Packages to not auto upgrade
    "auto_upgrade_ignore": [],
}
AmjadHD commented 3 years ago

yes I already did that, my question is whether that's the best way.

heyhusen commented 3 years ago

Hmm, I experienced something strange since yesterday. Previously, LSP could find Node.js in $PATH. But now it can't. On the other hand, LSP has no problem with rust-analyzer.

The changes I made earlier only changed my Desktop Environment. There shouldn't be any effect right?

Screenshot from 2021-09-29 09-35-14

rchl commented 3 years ago

What is the error exactly when it can't find node?

heyhusen commented 3 years ago

Sorry, I was not clear. The warning is more or less like the title of this isue.
All LSP-* packages that depend on Node.js, cannot be used.

Screenshot from 2021-09-29 15-12-46

Screenshot from 2021-09-29 15-13-21

rchl commented 3 years ago

Can you also check the ST console for related message? I think it might be complaining about version of Node being too old.

Ideally use Node 14 if you have something older.

heyhusen commented 3 years ago

Oh I'm sorry. Turns out I forgot to install npm. It's fine now.
Thank you very much.

bkoski commented 3 years ago

I suddenly ran into this issue as well. Moving the nvm init script from ~/.zshrc to ~/.zprofile as suggested above fixed it. Not entirely sure why it was working before? (helpful background on ST PROFILE handling in general here).

fwiw it seems a confusion is that many nvm install instructions (brew info, nvm README etc.) suggest .zshrc as a first choice for the init script rather than .zprofile.

kendfss commented 2 years ago

My solution was to just add

os.environ["PATH"] = os.pathsep.join(set(os.environ["PATH"].split(os.pathsep) + ["/usr/local/bin"]))

Near the top of every *.py file containing either os.getenv("PATH") or os.environ["PATH"]. It's heavy handed, clunky, and gross, but it worked. (sort of, now LSP doesn't always start on open... and I cannot seem to start it manually) Prior to that I duplicated my dotfiles to the appropriate profile/rc versions.

I think the fundamental issue is that Sublime's OS implementation is not reading the path from /etc/pass and doesn't look for dotfiles. Can't speak for Linux for n00b reasons, but almost everything on OSX gets linked into /usr/local/bin. You can't add links to the places on python's path variable with sudo, ime.

rchl commented 2 years ago

It would probably be better if you wouldn't suggest such, as you called it, "gross" solutions. There are already solutions that are clean and work so not sure why they wouldn't for you.

ST on macOS prints something like:

environment variables loaded using: /bin/zsh -l

in its console on start. If that doesn't error out then it does work as long as you've extended the PATH in the proper file (as described in LSP documentation linked in the initial comment).

kendfss commented 2 years ago

I've never seen that message before at all. Up until a handfull of reinstalls and manual clearances ago, I'd get ~20 lines in the console about watch activity, but never saw anything about environment variables. Now it's back to "normal" (more like I'm used to on windows) but still don't see anything about variables. Doesn't show up in a text search either.

Here's a breakdown of my experience with those docs > macOS | Depending on your default shell, edit: ~/.profile (bash), ~/.zprofile (zsh) or ~/.config/fish/config.fish (fish). One of the first things I did was copy `~/.zprofile` into `~/.profile`, `~/.zshrc`, and `~/.bashrc`. No effect. > export PATH="/usr/local/bin:$PATH" Was a redundant operation (`/usr/local/bin` was already in the path for all shells before the previous change was made) > For package managers like nvm (Node version manager), the recommended way is to insert its initialization script in the respective location specified above. I wasn't using nvm. Node is in `/usr/local/bin` (before and after brew re-installs). By chance, I did find an old nvm version, but removed it (was in the dotfiles, but still didn't show up in PATH). > Another solution could be (at least on Linux) to update the server PATH using the envparameter in your LSP configuration file. The following template can be used where: I had tried this, but it had no effect helpful effect because I'd already made the hack at that point.

The problem, before now, was that the LSP plguins simply would not start (for any of the dozen or so servers I'd installed. Trying to access through context menus was idempotent. Sometimes it would randomly start up, but disappear again as soon as I'd restart ST.

After a completely formatting all traces of ST under AppSupport and reinstalling (RIP my hotly exited notes, lol), it now seems to be behaving itself. We'll see how it goes (I think it's because I started with subl command).

condekind commented 2 years ago

... I want to avoid adding Node on every shell startup, so adding it through JSON configuration is excellent choice. I was under the impression that this will be used as PATH for that particular LSP implementation. ...

@niksy I have the exact same concern. I'm using nvm and none of the solutions worked for me. Adding the init as recommended to my shell rc file slows its startup time considerably:

# Taken from nvm repo (https://github.com/nvm-sh/nvm#install--update-script)
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

Before getting into sublime, it's important to say I had this function defined in my shell to address the slow init issue (NVM_DIR was already exported in my .profile equivalent):

# Set nvm
unalias setnvm 2>/dev/null
setnvm () {
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
}

Now, what fixed the issue with Sublime LSP-* for me was defining a wrapper function around subl (below the setnvm definition). Zsh users, this is my solution:

unalias subl 2>/dev/null; unset -f subl 2>/dev/null
subl() {
    if command -v nvm &>/dev/null; then
        PATH=$PATH $(whence -p subl) "$@"
    else
        setnvm
        PATH=$PATH $(whence -p subl) "$@"
    fi
}

Caveats: It probably won't work if you open sublime through a graphical interface (like clicking on a desktop[¹] menu or files in a file manager). I use a terminal for most things, so that "half" solution is enough for me.

Bash users, you can try this on your .bashrc or equivalent. No guarantees though:

unalias setnvm 2>/dev/null
setnvm () {
    if [ -z ${NVM_DIR+x} ]; then
        export NVM_DIR="${XDG_DATA_HOME:-"$HOME/.local/share"}/nvm"
        export NVM_SYMLINK_CURRENT=true
    fi

    if [ -z ${NPM_CONFIG_USERCONFIG+x} ]; then
        export NPM_CONFIG_USERCONFIG="${XDG_CONFIG_HOME:-"$HOME/.config"}/npm/npmrc"
    fi

    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
}

unalias subl 2>/dev/null; unset -f subl 2>/dev/null
subl() {
    if command -v nvm &>/dev/null; then
        PATH="$PATH" "$(type -P subl)" "$@"
    else
        setnvm
        PATH="$PATH" "$(type -P subl)" "$@"
    fi
}
[1] If that's important to you and you really found no other solution, try creating/editing the `Exec=` line of a sublime .desktop file (see the ones in \~/.local/share/applications for reference). I didn't try this, and I don't have such file for sublime, this is just a suggestion if nothing else worked.
niksy commented 2 years ago

@condekind yeah, that’s what I was thinking of doing, but I end up doing nothing and just making sure that Node is available in PATH on starting Sublime Text from terminal. It’s error prone, but I got muscle memory by now 😄

It would be great to have this natively!

rchl commented 2 years ago

@niksy I'm not planning on adding such option to lsp_utils. If you want to hardcode the path without using the nvm init script then it's as easy to do that in .zprofile as it would be in a dedicated lsp_utils option. And the latter would require a lot more changes to handle that.

niksy commented 2 years ago

@rchl understandable!

airtonix commented 2 years ago

This happens because for some reason the LSP developers decided to manage the installation of these tools.

You can see throughout the code base that they have class methods for storage_path and binary_path as in they expect to be managing these paths...

None of this would be a drama if instead:

Currently, all the LSP tools only work if I execute subl from the root of the project directory first.

If for some reason all the windows close (like when i logout of the desktop) and login again, launch sublime from desktop launcher, all the previously open windows (that had working scoped instances of LSP) now have broken instances of LSP because the CWD is different.

It's pretty annoying.

Another reason why LSP and co shouldn't be managing the installation or making assumptions about where the binaries are is that every project will use different versions of these tools (precisley the value proposition of asdf). LSP forces you to use incorrect versions of the tools across your projects.

change my mind.

rwols commented 2 years ago

change my mind.

I'm unsure if I can because it sounds like you're set in your ways, but I'll bite.

You can see throughout the code base that they have class methods for storage_path and binary_path as in they expect to be managing these paths...

Experience has shown that the majority of users enjoy this VSCode-esque level comfort.

If for some reason all the windows close (like when i logout of the desktop) and login again, launch sublime from desktop launcher, all the previously open windows (that had working scoped instances of LSP) now have broken instances of LSP because the CWD is different.

I'm fairly confused on what the problem is here. The current working directory should not matter for language servers.

If you want some kind of virtual-env-esque thing you should probably define custom client overrides in a .sublime-project or write your client config entirely in a .sublime-project file.

Another reason why LSP and co shouldn't be managing the installation or making assumptions about where the binaries are is that every project will use different versions of these tools (precisley the value proposition of asdf). LSP forces you to use incorrect versions of the tools across your projects.

It depends on the programming language whether that's a problem. Some language runtimes like Deno or Dart package the language server along with the runtime, which the ST package will then take care of. Others like LSP-typescript adapt to your typescript version of your project transparently. There has been some discussion about running things in docker containers which remains unresolved.

What server are we talking about here?

You can always manage things yourself by writing your client config in LSP.sublime-settings.

None of this would be a drama if instead:

There's really not much drama from my experience.

kendfss commented 2 years ago

Yo, not sure if I posted this here or not (sure I did on the sublimetext forums) but there's a plugin that fixes this issue on MacOS/OSX. It's called [ProjectEnvironment]() - it's also on package control. It's a shame to need an additional plug in for this, but I guess that's just the kind of suffering we signed up for when choosing sublime on mac... switched to linux about a week after finding this though lol

Here's a settings object. (the important bit is settings.osx)

// ProjectEnvironment.sublime-settings
// Settings in here override those in "/ProjectEnvironment/ProjectEnvironment.sublime-settings",
{
    // If true some debugging information will be preinted on console
    "print_output": false,
    // If true some variables available in Sublime's API, will be exposed as
    // standard environment variables.
    // these are:
    // "project_path", "project", "project_name", "project_base_name", "packages"
    "set_sublime_variables": false,
    // It may be useful to add a prefix to those variables so that they don't confict with yours
    "sublime_variables_prefix": "",
    // those variables can be all capitalised if you wish. "project" will become "PROJECT"
    "sublime_variables_capitalized": false,
    // files with this extensions will be run through source_vars(.bat|.sh)
    // DON'T FORGET THE DOT!
    "command_line_to_wrap_extensions": [
        ".bat",
        ".sh"
    ],
    // This is only for windows, since Mac and Linux can use shebang:
    "execute_ext_with": {
        ".py": "python",
        ".zsh": "zsh",
        ".sh": "zsh",
        ".bash": "bash"
    },
    "settings": {
        "project_environment": {
            "env": {},
            "env_file": "",
            "windows": {},
            "osx": {
                "PATH": "$PATH:/usr/local/bin",
                "env_file": "~/.zshenv"
            },
            "linux": {}
        }
    }
}

but yeah, this should allow your environment to persist across sessions.

kendfss commented 2 years ago

sorry, I think I used the wrong link before but my connection is so slow that I can't even edit my last post. Here's the ProjectEnvironment repo: https://bitbucket.org/daniele-niero/sublimeprojectenvironment

rwols commented 2 years ago

@kendfss,

For global PATH adjustments all you have to do is carefully read https://lsp.sublimetext.io/troubleshooting/#updating-the-path-used-by-lsp-servers

For per-project PATH adjustments, there's already a facility in LSP that can handle that. You can adjust the "env" key in the client configuration in your .sublime-project: https://lsp.sublimetext.io/guides/client_configuration/#client-configuration

kendfss commented 2 years ago

@rwols, cool, so why is this still open?

rwols commented 2 years ago

It's a sticky issue to guide people.

rchl commented 2 years ago

To be fair it can be closed and pinned. But maybe it should be just unpinned because with a lot of confusion that is going through the comments it might be more confusing than helpful.

jamesandres commented 1 year ago

Fyi, if you are using ZSH with oh-my-zsh, you may only have a ~/.zshrc file and not a ~/.zprofile.

What fixed this for me was to manually create an empty ~/.zprofile file with only the bits needed to adjust thePATH, as described in the guide.

This might be a root cause of confusion for people?

udoga commented 3 months ago

I had the same problem. I solved it by downloading Node.js without NVM and making sure that both "node" and "npm" binaries are accessible from my PATH (the LSP plugin looks for both). This way no additional configuration is needed in Sublime Text.