Skip to content

[Enhancement] show a warning or error if the language server gets an languageId that is not supported by RobotCode #575

Description

@UniqueActive

First 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:

  1. Open hx -v (with the language server configured)
  2. Open a robot file
  3. Open a different robot file
  4. 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)

Activity

  1. BrachystochroneSD commented on Mar 26, 2026

    @BrachystochroneSD

    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

  2. d-biehl commented on Mar 30, 2026

    @d-biehl
    Member

    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?

  3. BrachystochroneSD commented on Mar 31, 2026

    @BrachystochroneSD

    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)
    
  4. d-biehl commented on Mar 31, 2026

    @d-biehl
    Member

    super!!! @UniqueActive can you try this under helix?

  5. BrachystochroneSD commented on Mar 31, 2026

    @BrachystochroneSD

    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 ?

  6. UniqueActive commented on Mar 31, 2026

    @UniqueActive
    Author

    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.

  7. d-biehl commented on Mar 31, 2026

    @d-biehl
    Member

    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.

  8. d-biehl commented on Mar 31, 2026

    @d-biehl
    Member

    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.

  9. d-biehl commented on Mar 31, 2026

    @d-biehl
    Member

    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.

  10. BrachystochroneSD commented on Mar 31, 2026

    @BrachystochroneSD

    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

  11. d-biehl commented on Mar 31, 2026

    @d-biehl
    Member

    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...

  12. d-biehl commented on Apr 1, 2026

    @d-biehl
    Member

    sorry closed this to early, wanted to make it an enhancement ...

  13. reopened this on Apr 1, 2026
  14. 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, 2026
  15. added
    enhancementNew feature or request
    and removed
    bugSomething isn't working
    on Apr 1, 2026
  16. UniqueActive commented on Apr 2, 2026

    @UniqueActive
    Author

    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.

  17. added theissue type on Apr 7, 2026
  18. UniqueActive commented on May 28, 2026

    @UniqueActive
    Author

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions