GeezerVison is showing github.com — [Enhancement] show a warning or error if the language server gets an languageId that is not supported by RobotCode · Issue #575 · robotcodedev/robotcode
[Enhancement] show a warning or error if the language server gets an languageId that is not supported by RobotCode #575DescriptionFirst of all thank you for this awesome tool!
Describe the bug
I use Helix editor with robotcode language-server --stdio as a language server. I noticed that the file I open first or the files that are already open when robotcode is (re-)started are ignored by the language server - there are no suggestions and features like "go to definition" do not work, the language server seems to just return result null. But when I open another file after robotcode finished starting up, it all works fine for that file.
Below are some of the logs of the JSON messages (obtained from helix logs via hx -v) between the editor and language server, unfortunately I have not found an option to get more debug output out of the language server.
To me (as somebody who knows nothing about LSP) it looks like the first textDocument/didOpen is not handled properly by the language server which is why it does not provide diagnostics and just responds to methods like textDocument/definition with "result": null.
Steps To Reproduce
Steps to reproduce the behavior:
- Open
hx -v (with the language server configured)
- Open a robot file
- Open a different robot file
- Notice that the first-opened file does not have working LSP features (no suggestions, no goto definition) and the second one does
This was reproduced with a directory containing nothing but this file twice:
*** Test Cases ***
My Example Test
No Operation
Expected behavior
LSP features work for both opened files.
Logs
When opening the first file:
2026-02-26T09:43:13.862 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{"general":{"positionEncodings":["utf-8","utf-32","utf-16"]},"textDocument":{"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"]}},"dataSupport":true,"disabledSupport":true,"isPreferredSupport":true,"resolveSupport":{"properties":["edit","command"]}},"completion":{"completionItem":{"deprecatedSupport":true,"insertReplaceSupport":true,"resolveSupport":{"properties":["documentation","detail","additionalTextEdits"]},"snippetSupport":true,"tagSupport":{"valueSet":[1]}},"completionItemKind":{}},"formatting":{"dynamicRegistration":false},"hover":{"contentFormat":["markdown"]},"inlayHint":{"dynamicRegistration":false},"publishDiagnostics":{"tagSupport":{"valueSet":[1,2]},"versionSupport":true},"rename":{"dynamicRegistration":false,"honorsChangeAnnotations":false,"prepareSupport":true},"signatureHelp":{"signatureInformation":{"activeParameterSupport":true,"documentationFormat":["markdown"],"parameterInformation":{"labelOffsetSupport":true}}}},"window":{"workDoneProgress":true},"workspace":{"applyEdit":true,"configuration":true,"didChangeConfiguration":{"dynamicRegistration":false},"didChangeWatchedFiles":{"dynamicRegistration":true,"relativePatternSupport":false},"executeCommand":{"dynamicRegistration":false},"fileOperations":{"didRename":true,"willRename":true},"inlayHint":{"refreshSupport":false},"symbol":{"dynamicRegistration":false},"workspaceEdit":{"documentChanges":true,"failureHandling":"abort","normalizesLineEndings":false,"resourceOperations":["create","rename","delete"]},"workspaceFolders":true}},"clientInfo":{"name":"helix","version":"25.07.1 (a05c151b)"},"processId":25760,"rootPath":"/home/etaric/src/playground/robot/robotcode-bugreport","rootUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","workspaceFolders":[{"name":"robotcode-bugreport","uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport"}]},"id":0}
2026-02-26T09:43:14.277 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"positionEncoding":"utf-16","textDocumentSync":{"openClose":true,"change":2,"willSave":true,"willSaveWaitUntil":true,"save":{"includeText":true}},"completionProvider":{"triggerCharacters":[" ","*","\t",".","/","{","=","/"],"resolveProvider":true,"completionItem":{"labelDetailsSupport":true},"workDoneProgress":true},"hoverProvider":{"workDoneProgress":true},"signatureHelpProvider":{"triggerCharacters":[" ","\t"],"retriggerCharacters":[" ","\t"]},"definitionProvider":true,"implementationProvider":true,"referencesProvider":{"workDoneProgress":true},"documentHighlightProvider":{"workDoneProgress":true},"codeActionProvider":{"codeActionKinds":["refactor.extract.function","refactor.surround","quickfix","source"],"resolveProvider":true},"codeLensProvider":{"resolveProvider":true},"workspaceSymbolProvider":true,"documentFormattingProvider":{"workDoneProgress":true},"documentRangeFormattingProvider":{"workDoneProgress":true},"renameProvider":{"prepareProvider":true,"workDoneProgress":true},"foldingRangeProvider":true,"selectionRangeProvider":{"workDoneProgress":true},"executeCommandProvider":{"commands":[]},"semanticTokensProvider":{"legend":{"tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator","decorator","settingImport","setting","header","headerSettings","headerVariable","headerTestcase","headerTask","headerComment","headerKeyword","testcaseName","keywordName","controlFlow","argument","variable","keywordCall","keywordCallInner","bddPrefix","nameCall","continuation","separator","terminator","forSeparator","variableBegin","variableEnd","expressionBegin","expressionEnd","variableExpression","escape","namespace","error","config","namedArgument","var","documentation"],"tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary","builtin","embedded"]},"full":true},"inlineValueProvider":{"workDoneProgress":true,"documentSelector":[{"language":"robotframework"}]},"inlayHintProvider":{},"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":"81bd7109-5584-4549-951a-4d6f8e0c7854"},"fileOperations":{"didCreate":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"willCreate":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"didRename":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"willRename":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"didDelete":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]},"willDelete":{"filters":[{"pattern":{"glob":"**/*.{yaml,robot,py,yml,resource}"}}]}}}},"serverInfo":{"name":"RobotCode Language Server","version":"2.2.0"}}}
2026-02-26T09:43:14.277 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"initialized","params":{}}
2026-02-26T09:43:14.277 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"languageId":"robot","text":"*** Test Cases ***\nMy Example Test\n No Operation\n","uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example0.robot","version":0}}}
2026-02-26T09:43:14.282 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":1,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.robot"}]}}
2026-02-26T09:43:14.282 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":1}
2026-02-26T09:43:14.283 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":2,"method":"workspace/configuration","params":{"items":[{"section":"robotcode.documentationServer"}]}}
2026-02-26T09:43:14.283 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":2}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":3,"method":"client/registerCapability","params":{"registrations":[{"id":"16a6790d-b40e-45cf-81da-465edcc35d3c","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"**/*.{robot,resource}","kind":5}]}}]}}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":4,"method":"client/registerCapability","params":{"registrations":[{"id":"81875a4e-36d0-48aa-b7cc-0cc07b743b2b","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"**/*.{yaml,robot,py,yml,resource}","kind":7}]}}]}}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":3}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":4}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":5,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode"}]}}
2026-02-26T09:43:14.287 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":5}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":6,"method":"window/workDoneProgress/create","params":{"token":"55c1db6c-d785-4ec6-b327-d40ced0da6e0"}}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"55c1db6c-d785-4ec6-b327-d40ced0da6e0","value":{"title":"RobotCode","kind":"begin","cancellable":false,"message":"Collect sources"}}}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":6}
2026-02-26T09:43:14.289 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"55c1db6c-d785-4ec6-b327-d40ced0da6e0","value":{"kind":"end"}}}
2026-02-26T09:43:14.290 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":7,"method":"window/workDoneProgress/create","params":{"token":"1d14484b-1e49-4f5f-b76e-1160af9c4d05"}}
2026-02-26T09:43:14.290 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":7}
2026-02-26T09:43:14.291 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"1d14484b-1e49-4f5f-b76e-1160af9c4d05","value":{"kind":"end"}}}
2026-02-26T09:43:14.291 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":8,"method":"window/workDoneProgress/create","params":{"token":"ca545fc4-9e0e-44f3-90f6-c0da1653e615"}}
2026-02-26T09:43:14.291 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":8}
2026-02-26T09:43:14.292 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":9,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example0.robot","section":"robotcode.analysis"}]}}
2026-02-26T09:43:14.292 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":9}
2026-02-26T09:43:14.295 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":10,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.analysis.cache"}]}}
2026-02-26T09:43:14.295 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":10}
2026-02-26T09:43:14.296 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":11,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.analysis.robot"}]}}
2026-02-26T09:43:14.296 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":11}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":12,"method":"client/registerCapability","params":{"registrations":[{"id":"2f280da0-f312-46d6-b11a-88286b83e3a3","method":"workspace/didChangeWatchedFiles","registerOptions":{"watchers":[{"globPattern":"/home/etaric/src/playground/robot/robotcode-bugreport/.venv/lib/python3.12/site-packages/robot/libraries/**"}]}}]}}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"ca545fc4-9e0e-44f3-90f6-c0da1653e615","value":{"kind":"end"}}}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":13,"method":"window/workDoneProgress/create","params":{"token":"60791b17-44dc-4e1f-8c87-6ca5196aa819"}}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":12}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":13}
2026-02-26T09:43:14.306 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"60791b17-44dc-4e1f-8c87-6ca5196aa819","value":{"kind":"end"}}}
When opening the second file:
2026-02-26T09:46:35.075 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"languageId":"robot","text":"*** Test Cases ***\nMy Example Test\n No Operation\n","uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","version":0}}}
2026-02-26T09:46:36.375 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":14,"method":"window/workDoneProgress/create","params":{"token":"218fc89b-a36a-4a64-a757-973245785ef6"}}
2026-02-26T09:46:36.376 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":14}
2026-02-26T09:46:36.378 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"218fc89b-a36a-4a64-a757-973245785ef6","value":{"kind":"end"}}}
2026-02-26T09:46:36.379 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":15,"method":"window/workDoneProgress/create","params":{"token":"2a551ba2-b411-46f7-b0d1-da91bee6ae69"}}
2026-02-26T09:46:36.379 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":16,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport","section":"robotcode.robocop"}]}}
2026-02-26T09:46:36.380 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":null,"id":15}
2026-02-26T09:46:36.380 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":16}
2026-02-26T09:46:36.452 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":17,"method":"workspace/configuration","params":{"items":[{"scopeUri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","section":"robotcode.analysis.diagnosticModifiers"}]}}
2026-02-26T09:46:36.452 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","result":[null],"id":17}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example1.robot","diagnostics":[{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":15}},"message":"Missing documentation in 'My Example Test' test case","severity":2,"code":"DOC02-missing-doc-test-case","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc02-missing-doc-test-case"},"source":"robocop"},{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":0}},"message":"Missing documentation in suite","severity":2,"code":"DOC03-missing-doc-suite","codeDescription":{"href":"https://robocop.dev/v6.10.1/rules/rules_list.html#doc03-missing-doc-suite"},"source":"robocop"}],"version":0}}
2026-02-26T09:46:36.454 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","method":"$/progress","params":{"token":"2a551ba2-b411-46f7-b0d1-da91bee6ae69","value":{"kind":"end"}}}
When doing a go to definition in the first file:
2026-02-26T09:56:30.003 helix_lsp::transport [INFO] robotcode -> {"jsonrpc":"2.0","method":"textDocument/definition","params":{"position":{"character":8,"line":2},"textDocument":{"uri":"file:///home/etaric/src/playground/robot/robotcode-bugreport/example0.robot"}},"id":1}
2026-02-26T09:56:30.008 helix_lsp::transport [INFO] robotcode <- {"jsonrpc":"2.0","id":1,"result":null}
Additional context
None
Desktop (please complete the following information):
- Helix version: helix 25.07.1 (a05c151b)
- RobotCode Version: robotcode, version 2.2.0
- OS: Ubuntu 24.04.4 LTS
- Python Version: Python 3.12.3 (also tested with 3.13.12)
- RobotFramework Version: Robot Framework 7.4.1 (Python 3.12.3 on linux)
- RoboCop Version: robocop, version 6.10.1 (got no suggestions on 8.X)
ActivityBrachystochroneSD commented on Mar 26, 2026 I can reproduce the same behavior with Emacs + Eglot: the file that is already open when Eglot starts RobotCode gets no LSP features (no diagnostics, completion, goto definition; requests return null). Files opened after the server has finished starting work normally.
It looks like RobotCode doesn’t handle an “early” textDocument/didOpen (sent right after initialized) correctly. In the failing trace, didOpen happens before RobotCode finishes its workspace/configuration phase; in the working trace, didOpen happens after more configuration/setup, and then diagnostics start.
Here is the failing trace (didOpen very early; no publishDiagnostics ever for that URI)
[jsonrpc] D[15:36:40.874] Running language server: robotcode language-server
...
[jsonrpc] e[15:36:41.457] --> initialized {"jsonrpc":"2.0","method":"initialized","params":{}}
[jsonrpc] e[15:36:41.463] --> textDocument/didOpen {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///home/sam/robot-project/hello.robot","version":0,"languageId":"robot","text":"..."}}}
[jsonrpc] e[15:36:41.686] <-- workspace/configuration[3] ... "section":"robotcode.robot"
[jsonrpc] e[15:36:41.726] <-- workspace/configuration[6] ... "section":"robotcode.analysis"
...
;; afterwards, requests like signatureHelp/definition return result:null
;; and there is NO textDocument/publishDiagnostics for hello.robot
Working trace (open file after server startup; diagnostics published)
[jsonrpc] D[15:39:32.706] Running language server: robotcode language-server
...
[jsonrpc] e[15:39:33.321] --> initialized {"jsonrpc":"2.0","method":"initialized","params":{}}
... (more workspace/configuration + capability registration happens)
[jsonrpc] e[15:39:46.095] --> textDocument/didOpen {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///home/sam/robot-project/hello.robot","version":0,"languageId":"robot","text":"..."}}}
...
[jsonrpc] e[15:39:47.651] <-- textDocument/publishDiagnostics {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/sam/robot-project/hello.robot","diagnostics":[],"version":0}}
For comparison, robotframework_ls works fine even when didOpen is sent immediately after initialized (it publishes diagnostics for the initially opened file):
[jsonrpc] D[15:54:09.589] Running language server: robotframework_ls
...
[jsonrpc] e[15:54:09.785] --> initialized {"jsonrpc":"2.0","method":"initialized","params":{}}
[jsonrpc] e[15:54:09.791] --> textDocument/didOpen {"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///home/sam/robot-project/hello.robot","version":0,"languageId":"robot","text":"..."}}}
...
[jsonrpc] e[15:54:10.592] <-- textDocument/publishDiagnostics {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///home/sam/robot-project/hello.robot","diagnostics":[]}}
This shows another Robot Framework LS handles the same ordering correctly (diagnostics are published for the initially opened file), so the issue is specific to RobotCode’s handling of early didOpen / initialization.
Environment:
- Emacs + Eglot 1.17.30
- RobotCode 2.4.0
- Linux
EDIT: Note that in helix logs and mine, the languageid is set to robot and not robotframework, let me investigate a bit d-biehl commented on Mar 30, 2026 Sorry, I do not currently have Helix or Emacs set up, and I do not have enough time right now to test them properly.
One possible explanation is that the languageId is being set to robot instead of robotframework. At the moment, the language server only supports robotframework as the languageId.
I know that this works with Neovim using LSP support, and I have also tested it successfully with other editors such as Kate and QtCreator.
Could you try changing the languageId to robotframework and see whether that fixes the problem? BrachystochroneSD commented on Mar 31, 2026 I think that was the issue indeed!
seems to work when enforcing the language id (within emacs):
(push (cons '(robot-mode :language-id "robotframework") '("robotcode" "language-server"))
eglot-server-programs)
d-biehl commented on Mar 31, 2026 BrachystochroneSD commented on Mar 31, 2026 Note that it was hard to find the root cause, and the language server somehow was kind of work even with a wrong language id.
Maybe I miss something but wouldn't the language server fail with a message stating that the language id is not supported ? UniqueActive commented on Mar 31, 2026 Hi, thank you for looking into it @d-biehl ! I tried helix with languageId set to "robotframework" and it works correctly now.
It would be nice to have one of these solutions:
- Both IDs are supported (preferred, since there is no ID specified at all for Robot Framework in the LSP specification - please correct me if I am missing something)
- invalid
languageId results in an error, not this strange semi-working state ;)
If you don't intend on supporting the language id "robot" then I'll get this changed in helix's upstream default configuration. d-biehl commented on Mar 31, 2026 I need to take a deeper look at this, but I think the important part here is how languageId is intended to work in LSP.
According to the LSP specification, text documents have a languageId so the server can identify the document language “to avoid re-interpreting the file extension”. It also says that for some listed programming languages certain ids are recommended, but that is a recommendation for those listed languages, not a general rule that every language must use one short or obvious identifier.
That is also why I do not think the server should try to re-classify files purely from their extension. The client is the component that opens the document and decides which languageId it gets. The server is supposed to use that classification, not guess it again from the path.
This is especially relevant for Robot Framework, because Robot Framework is not tied to a single extension. Resource files are recommended to use .resource, but for backwards compatibility .robot, .txt, and .tsv also work. In addition, Robot Framework also supports reStructuredText-based files such as .rst and .rest, and JSON-based files such as .json and .rsrc. So there is not a single extension that uniquely identifies “this is definitely Robot Framework”. On the contrary, several of these extensions clearly have meanings outside Robot Framework as well: .txt is completely generic, .rst/.rest are associated with reStructuredText in general, and .json is of course a generic data format used everywhere.
Because of that, I intentionally chose robotframework as the language id and not just robot.
For me, robotframework is the more precise and less ambiguous identifier. robot is too generic, and it is also already used by other tools in other contexts. If a client wants Robot Framework language features to work correctly, then the client should classify the document accordingly and use the proper languageId when opening it.
So from my point of view, the issue is not that the server should switch to robot, but that the client must decide which languageId a file gets, and the server then uses exactly that classification. d-biehl commented on Mar 31, 2026 I do not really know how this is configured in Helix or Emacs specifically, but I would assume they have some equivalent mechanism on the client side to decide how files are classified and which languageId is sent to the server, similar to how this is configured in VS Code. d-biehl commented on Mar 31, 2026 Also, if either of you already has a working Helix or Emacs setup for RobotCode, would you maybe be interested in contributing a small documentation section for that? We already have a small setup guide for Neovim, so it would be great to have similar documentation for other editors as well:
https://robotcode.io/04_tip_and_tricks/04_neovim_lsp_setup
I think that would probably help other users more than trying to make the server compensate for editor-specific client configuration issues. BrachystochroneSD commented on Mar 31, 2026 I agree with your points about languageId, the client is responsible for classifying documents, and robotframework is the right choice given the ambiguity of robot and the variety of file extensions Robot Framework supports.
From the Emacs side, the root cause is robot-mode, which predates the broader file extension support and only associates with .robot files. It sets the language id to robot rather than robotframework. That's something to fix on the client/mode side, not in the server, no disagreement there.
That said, one small improvement that could help users across all editors: when the server receives a textDocument/didOpen with a languageId that isn't robotframework but the file extension suggests it could be a Robot Framework file (.robot, .resource, etc.), the server could send a window/showMessage warning, something like:
"Document opened with languageId 'robot', but RobotCode expects 'robotframework'. Some features may not work correctly. Please configure your editor to use the correct languageId."
This wouldn't change any server behavior or add any file-extension guessing logic. It's just a one-time hint to the user that their client configuration is off. Right now the server continue to work silently, which is hard to diagnose and leads to issues like this one being opened. A visible message would point people to the fix immediately, and redirect the problem to the client/modes.
Regarding the Emacs documentation, I'd be happy to contribute d-biehl commented on Mar 31, 2026
Regarding the Emacs documentation, I'd be happy to contribute
very cool!!!
I am not sure if a message is the right solution, maybe a log or a critical warning message in the log output or something like this, have to think about it... d-biehl commented on Apr 1, 2026 sorry closed this to early, wanted to make it an enhancement ... changed the title [-][BUG] language-server ignores files opened early[/-] [+][Enhancement] show a warning or error if the language server gets an languageId that is not supported by RobotCode[/+] on Apr 1, 2026UniqueActive commented on Apr 2, 2026 Thank you for the detailed explanation regarding languageId, it makes sense to keep robotframework here and instead just make this a logging enhancement. :)
Regarding making a guide: helix has built-in LSP support and ships with language server configurations. I will update the upstream configuration with the correct languageId so that it should simply work out of the box, then a user would only need to install robotcode's language server - I don't think a guide is needed for that. UniqueActive commented on May 28, 2026 My MR for fixed support in Helix was merged a few days ago so robotcode is supported properly in Helix master. A release was not tagged yet though.
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|