LSP stops because of an error I don't understand

When running the Psalm language server in my Psalm extension it starts up fine but never finishes analyzing a file because of an error I receive that I’m not sure what to do about, saying The data couldn't be read because it is missing:

I’m pretty sure this is not an error coming from Psalm since I can’t find this string in the Psalm codebase, so I’m wondering if this could be coming from Nova? Another point to consider is that when I initially published the extension it was working fine. I forget which version of Nova I had at the time, but this may be a regression in the LSP support?

I’m not really sure how to start debugging this so I’d appreciate it if y’all could take a look on your end. For the extension to work you need to have PHP, Composer, and Psalm on your computer.

Getting set up for testing

  1. Install PHP on your computer. I recommend using homebrew.
  2. Install composer on your computer:
# This is copied from the page I linked to above, but I'd recommend going there yourself to read the instructions.

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
sudo mv composer.phar /usr/local/bin/composer # not strictly necessary, you can also run the PHAR file from wherever it is installed and delete it after testing.
  1. Create a directory with a test file:
mkdir test-psalm
cd test-psalm
touch test-file.php
  1. Add the following code to the test file:
<?php

/**
 * @return array<string>
 */
function takesAnInt(int $i) {
	return [$i, "hello"];
}

$data = ["some text", 5];
takesAnInt($data[0]);

$condition = rand(0, 5);
if ($condition) {
} elseif ($condition) {}
  1. Install psalm in the test folder and generate a config file:
cd test-psalm # If you're not in the test directory already
/path/to/composer require --dev vimeo/psalm # change /path/to/composer to wherever the .phar file is
./vendor/bin/psalm --init
  1. Make sure psalm runs correctly normally (i.e. not the LSP way used in the extension)
./vendor/bin/psalm --no-cache test-file.php
  1. Install the Psalm extension.
  2. Add the test project to Nova and open the test file.
  3. Notice the Psalm extension/LSP will run and send/receive several messages, but it won’t highlight the issues (like shown on the screenshot in the plugin readme). It doesn’t highlight the issue because the language server stops after running into the issue. Instead you’ll get a notification from the extension saying Psalm stopped. If you check the extension console you’ll see the The data couldn't be read because it is missing message. The error parameter passed to onDidStop seems to be a string (the message in the extension console) which is why the notice body is undefined; it’s expecting an object with a message property.

Hi Kristófer,

This sounds like a JSON decoding issue on Nova’s side. I’ll set up with your steps and see if perhaps the Psalm language server is sending an LSP message Nova isn’t decoding properly.

Logan

Alright. I think I’ve found the issue.

For certain capabilities in the LSP Initialize request, the Psalm language server is sending a value of null instead of leaving out the key, and Nova isn’t handling this properly for all capabilities. Nothing related to this has changed lately with Nova (in the last year), so my guess is that at some point recently Psalm made a change that is now causing that, perhaps?

Either way, they are still within spec, and it’s Nova’s issue to fix, which I will do so for our next beta release of Nova 10.

Thank you for the report!

Logan

2 Likes

Awesome, thank you for looking into this @logan! :pray:

I can confirm Nova 10 fixed the issue. Thank you @logan, Nova 10 looks amazing! :star_struck:

1 Like