I created an extension to use Intelephense as a language server for PHP development a while ago, but it creates some problems with the extension runtime.
Once the language server is activated Nova’s extension runtime becomes somewhat unstable, and I sometimes have to restart extensions to get them to work properly after the crash.
How to reproduce the problem
- Install Intelephense via
sudo npm install intelephense@1.5.4 -g
- Install the Intelephense Nova extension from the extension library
An overview of the problem
Because of an uncaught exception in one of Intelephense’s dependencies Nova’s extension runtime crashes, and subsequently becomes unstable. The exception doesn’t seem to interrupt the execution of Intelephense, but Nova’s extension runtime crashes.
Because of the nature of how this error occurs, I don’t think the extension runtime should be crashing.
But first:
Why does this happen?
Intelephense is run via Nova’s LanguageClient API, using the system’s node
installation. In the extension’s code you’ll see Intelephense invoked directly via /usr/local/bin/intelephense
, but that executable is just a node script with a #! /usr/bin/env node
at the top, and as such is executed as a node process. Pointing the LanguageClient
at node /usr/local/bin/intelephense
makes no difference.
During initialization there’s a bug in one of Intelephense’s dependencies that causes the workspace/didChangeFolders
registration to fail with an uncaught exception:
Intelephense Language Server[17:44:37.632000] (node:40100) UnhandledPromiseRejectionWarning: Error: Invalid parameter: registrations
Intelephense Language Server[17:44:37.632000] Registrations must be of type Registration[]
Intelephense Language Server[17:44:37.632000] at /usr/local/lib/node_modules/intelephense/lib/intelephense.js:59:95679
Intelephense Language Server[17:44:37.632000] at /usr/local/lib/node_modules/intelephense/lib/intelephense.js:59:95973
Intelephense Language Server[17:44:37.632000] at Immediate.<anonymous> (/usr/local/lib/node_modules/intelephense/lib/intelephense.js:59:96334)
Intelephense Language Server[17:44:37.632000] at processImmediate (internal/timers.js:461:21)
Intelephense Language Server[17:44:37.632000] (Use `node --trace-warnings ...` to show where the warning was created)
Intelephense Language Server[17:44:37.632000] (node:40100) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
Intelephense Language Server[17:44:37.632000] (node:40100) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Even though this uncaught exception happens in a subprocess and Intelephense keeps running in the background, the error bubbles up to Nova’s extension runtime:
The extension is fully functional after this (I just click “OK”), and I can use Intelephense (mostly) without any problems:
What’s happened so far
I reported this problem in the Intelephense repo but the author can’t fix the problem because it’s an issue with one of their fundamental dependencies: vscode-language-server-node. The issue has actually been fixed but because vscode-language-server-node is on a really slow release cycle the fix hasn’t been released yet, and as such Intelephense continues to be unstable with Nova.
I’ve tried various methods of wrapping the LanguageClient
invocation in try/catch
blocks to try to manage the exception, but it doesn’t work.
I do expect this will be fixed in Intelephense as soon as they can update their dependencies, but I also think Nova’s extension runtime should not crash because of this issue. Even though the exception is uncaught, I believe it should be handled by the node process, and shouldn’t affect Nova’s extension runtime. The reason I arrived at this conclusion is because the server continues to function properly even after the crash.
My best guess is that there’s some interference happening because Nova’s extension engine is a JS runtime that’s running a Node process, and that’s why the exception bubbles up to the extension runtime.
I don’t think should require changes in the LanguageClient API because the problem stems from some vagueness in the LSP spec and forcing dynamicRegistration
on if the server decides to provide support, without giving the client the option to opt out of it.
Summary
- While there’s an uncaught exception in Intelephense, the server and extension continue to function correctly.
- Nova’s extension runtime is affected by this uncaught exception, despite the
node
process seemingly handling the crash. - Because Nova’s extension runtime crashes, other extensions must be restarted to function properly.
- A fix exists for Intelephense, but it hasn’t been deployed yet, and probably won’t be for another month or 2.
- A change to the LanguageClient API is probably not needed
- A change to the extension runtime might be needed? Maybe the
Process
API?
I don’t know if this is something you can/should/need to fix, but it seemed prudent to at least report this so you can take a look at what’s happening
I’d love to hear your thoughts on this, and hope this is something that you can fix
Let me know if you need more information or if there’s anything else I can do to help!