Nova's extension runtime crashes when there's an uncaught exception in a running node.js based LanguageClient process

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

  1. Install Intelephense via sudo npm install intelephense@1.5.4 -g
  2. 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 :slight_smile:

I’d love to hear your thoughts on this, and hope this is something that you can fix :relaxed:
Let me know if you need more information or if there’s anything else I can do to help!

1 Like

After posting this I just tried the latest version of Intelephense; v1.6.3. It seems that version has a different issue that causes the language server to index files indefinitely, and thus not work. This seems to be happening for all the v1.6.x versions.

It just occurred to me now that I’ve been using an old version of Intelephense; v.1.3.0-beta. So I’ve gone back to find a working version that still shows this same issue.

I’ve changed the original reproduction steps to install v1.5.4 via sudo npm install -g intelephense@1.5.4 . Sorry about the confusion here!

Hello Kristófer,

Thank you for the report. You’re right; No matter what, the extension service should not crash even if there’s something in the extension’s dependencies failing.

If possible, could you attach a crash report from the NovaExtensionService process? They should be in ~/Library/Logs/DiagnosticReports/. This would help me figure out exactly what call might be causing the service to crash.

I can try and reproduce this on my side with you extension as well in the short term.

2 Likes

I wasn’t able to attach the file to the post, and the contents of the file are too long to leave in a comment, so I uploaded the contents to paste.sr.ht.

I hope this helps!

Just wanted to let you know that we’ve found the source of this crash, and should have a fix in the next bug fix release of Nova soon.

3 Likes

That’s awesome, thank you!