charmbracelet / charmbracelet/x

powernap advertises `workspace/workspaceFolders` but lacks handler; router panics on nil params

Open
#610 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
314
Forks
94
Avg merge
3d 22h
Merged PRs (30d)
2

Description

### Description

## Describe the bug

- powernap advertises `capabilities.workspace.workspaceFolders: true` during initialize but didn’t register a handler for `workspace/workspaceFolders` (server-initiated request). Servers like MATLAB-language-server call this method immediately and get `no handler for method: workspace/workspaceFolders`.
- Separately, Router.Route dereferenced `*req.Params` without a nil check, so a server request/notification with no params could panic the client.

## To Reproduce

1. Run Crush v0.13.6 (which uses x/powernap at 25f979b54ad4) against [MATLAB-language-server](https://github.com/mathworks/MATLAB-language-server).
2. After initialize/initialized, the server calls `workspace/workspaceFolders` with no params.
3. Error from missing handler; or panic in Router when Params is nil.

## Expected behavior

- If the client (powernap) advertises workspaceFolders, it must respond with configured folders (or empty array).
- Router should accept nil Params safely for both requests and notifications.

## Actual behavior

- Server calls `workspace/workspaceFolders`; client returns error: "no handler for method: workspace/workspaceFolders".
- If a handler for `workspace/workspaceFolders` is added, client panics in Router when `req.Params` is nil.

## Setup

- Crush v0.13.6
- powernap v0.0.0-20251015113943-25f979b54ad4
- LSP Server: [MATLAB-language-server](https://github.com/mathworks/MATLAB-language-server) v1.3.6
- Ubuntu 24.04.3 LTS as devcontainer (mcr.microsoft.com/devcontainers/base:ubuntu-24.04)

## Source Code

- Affected code:
- pkg/lsp/client.go — advertises `workspaceFolders: true`; no handler registered for `workspace/workspaceFolders`.
- pkg/transport/router.go — Router.Route dereferences `*req.Params` without a nil check.

## Additional context

- Impacts servers that call `workspace/workspaceFolders` early in startup (e.g., MATLAB-language-server).

Example traffic between `crush` and `matlab-language-server`

### Example traffic between `crush` and `matlab-language-server`

`stdin`:

```json
Content-Length: 2837

{"id":0,"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{"general":{"markdown":{"parser":"marked","version":"1.1.0"},"positionEncodings":["utf-16"],"regularExpressions":{"engine":"ECMAScript","version":"ES2020"}},"textDocument":{"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"dataSupport":true,"dynamicRegistration":true,"isPreferredSupport":true,"resolveSupport":{"properties":["edit"]}},"completion":{"completionItem":{"commitCharactersSupport":true,"deprecatedSupport":true,"documentationFormat":["markdown","plaintext"],"insertReplaceSupport":true,"preselectSupport":true,"resolveSupport":{"properties":["documentation","detail","additionalTextEdits"]},"snippetSupport":false,"tagSupport":{"valueSet":[1]}},"contextSupport":true,"dynamicRegistration":true},"definition":{"dynamicRegistration":true,"linkSupport":true},"documentHighlight":{"dynamicRegistration":true},"documentSymbol":{"dynamicRegistration":true,"hierarchicalDocumentSymbolSupport":true},"formatting":{"dynamicRegistration":true},"hover":{"contentFormat":["markdown","plaintext"],"dynamicRegistration":true},"publishDiagnostics":{"codeDescriptionSupport":true,"dataSupport":true,"relatedInformation":true,"tagSupport":{"valueSet":[1,2]},"versionSupport":true},"rangeFormatting":{"dynamicRegistration":true},"references":{"dynamicRegistration":true},"rename":{"dynamicRegistration":true,"prepareSupport":true},"synchronization":{"didSave":true,"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":true}},"window":{"showDocument":{"support":true},"showMessage":{"messageActionItem":{"additionalPropertiesSupport":true}},"workDoneProgress":true},"workspace":{"applyEdit":true,"configuration":true,"didChangeConfiguration":{"dynamicRegistration":true},"didChangeWatchedFiles":{"dynamicRegistration":true,"relativePatternSupport":true},"fileOperations":{"didCreate":true,"didDelete":true,"didRename":true,"dynamicRegistration":true,"willCreate":true,"willDelete":true,"willRename":true},"symbol":{"dynamicRegistration":true},"workspaceEdit":{"documentChanges":true,"failureHandling":"textOnlyTransactional","normalizesLineEndings":true,"resourceOperations":["create","rename","delete"]},"workspaceFolders":true}},"clientInfo":{"name":"powernap","version":"0.1.0"},"initializationOptions":{"MATLAB":{"indexWorkspace":true,"installPath":"/opt/matlab/R2025b","matlabConnectionTiming":"onStart","prewarmGraphics":false,"signIn":true,"telemetry":false}},"locale":"en-us","processId":26471,"rootPath":"/workspaces/agentic-matlab-example","rootUri":"file:///workspaces/agentic-matlab-example","trace":"off","workspaceFolders":[{"uri":"file:///workspaces/agentic-matlab-example","name":"agentic-matlab-example"}]}}Content-Length: 52

{"jsonrpc":"2.0","method":"initialized","params":{}}Content-Length: 38

{"id":0,"result":null,"jsonrpc":"2.0"}Content-Length: 38

{"id":1,"result":[{}],"jsonrpc":"2.0"}Content-Length: 38

{"id":2,"result":null,"jsonrpc":"2.0"}Content-Length: 105

{"id":3,"error":{"code":0,"message":"no handler for method: workspace/workspaceFolders"},"jsonrpc":"2.0"}
```

`stdout`:

```json
Content-Length: 134

{"jsonrpc":"2.0","method":"window/logMessage","params":{"type":4,"message":"(17:12:36) matlabls: Log Directory: /tmp/matlabls_26511"}}Content-Length: 583

{"jsonrpc":"2.0","id":0,"result":{"capabilities":{"codeActionProvider":true,"completionProvider":{"triggerCharacters":[".","("," ",",","/","\\"]},"definitionProvider":true,"documentFormattingProvider":true,"documentRangeFormattingProvider":true,"executeCommandProvider":{"commands":["matlabls.lint.suppress.line","matlabls.lint.suppress.file"]},"foldingRangeProvider":true,"referencesProvider":true,"signatureHelpProvider":{"triggerCharacters":["(",","]},"documentSymbolProvider":true,"renameProvider":{"prepareProvider":true},"documentHighlightProvider":true,"textDocumentSync":2}}}Content-Length: 201

{"jsonrpc":"2.0","id":0,"method":"client/registerCapability","params":{"registrations":[{"id":"91b68732-e3ec-49a1-bfb6-1202b45aad6f","method":"workspace/didChangeConfiguration","registerOptions":{}}]}}Content-Length: 101

{"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"section":"MATLAB"}]}}Content-Length: 204

{"jsonrpc":"2.0","id":2,"method":"client/registerCapability","params":{"registrations":[{"id":"93246463-a499-485b-b7af-5c7110954b4d","method":"workspace/didChangeWorkspaceFolders","registerOptions":{}}]}}Content-Length: 103

{"jsonrpc":"2.0","method":"matlab/connection/update/server","params":{"connectionStatus":"connecting"}}Content-Length: 62

{"jsonrpc":"2.0","id":3,"method":"workspace/workspaceFolders"}
```

`stderr`:

```plaintext
(node:26511) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
/opt/matlab-language-server/out/index.js:43412
responsePromise.reject(new messages_1.ResponseError(error.code, error.message, error.data));
^

ResponseError: no handler for method: workspace/workspaceFolders
at handleResponse (/opt/matlab-language-server/out/index.js:43412:48)
at handleMessage (/opt/matlab-language-server/out/index.js:43192:13)
at processMessageQueue (/opt/matlab-language-server/out/index.js:43209:17)
at Immediate. (/opt/matlab-language-server/out/index.js:43181:13)
at process.processImmediate (node:internal/timers:485:21) {
code: 0,
data: undefined
}

Node.js v22.21.1
```

Example `crush.json` lsp config for `matlab-language-server`

### Example `crush.json` lsp config for `matlab-language-server`

```json
{
"$schema": "https://charm.land/crush.json",
"lsp": {
"matlab": {
"command": "/usr/local/bin/matlab-language-server",
"args": [
"--stdio"
],
"env": {
"MLM_LICENSE_FILE": "27000@host"
},
"init_options": {
"MATLAB": {
"installPath": "/opt/matlab/R2025b",
"indexWorkspace": true,
"matlabConnectionTiming": "onStart",
"telemetry": false,
"signIn": true,
"prewarmGraphics": false
}
}
}
},
...
}
```

### Version

_No response_

### Environment

_No response_

Contributor guide

Open the contributing guide

Research direction

Start in pkg/lsp/client.go to inspect the advertised workspaceFolders capability and handler registration, then read pkg/transport/router.go where Router.Route dereferences req.Params. The change is done when workspace/workspaceFolders returns configured folders or an empty array and nil params no longer panic for requests or notifications; verify with the repository's relevant tests if available.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.