I ran into an issue with either Emacs, eglot, or jetls. @aviatesk was unable to reproduce it, so I made a minimal reproducible environment with straight.el at
I wonder if anyone can reproduce the issue running from ./run.sh, and if file.jl is otherwise fine in your standard config, how the versions of the relevant packages differ.
I really want to use jetls but there may be an issue lurking in my setup that I need to track down to make the experience hassle-free.
Thanks for putting together the MWE.
I dug into this and the eglot error message itself is a strong signal:
(args-out-of-range “inplace_∂g∂x_v!(x)” 21 22)
The string “inplace_∂g∂x_v!(x)” has:
18 characters
22 bytes in UTF-8 (each ∂ takes 3 bytes)
18 UTF-16 code units (∂ is in the BMP)
The args 21 22 only match the UTF-8 byte length. Emacs string indexing is character-based, so accessing index 21–22 in an 18-character string blows up. So eglot has a code path that’s receiving UTF-8 byte offsets but using them as Emacs character positions without converting. That a timer fires it suggests something in the eldoc / hover-related-info display.
What JETLS does: it checks general.positionEncodings from the client and prefers UTF-8 if advertised (since UTF-8 is the native encoding for Julia strings — no conversion needed server-side), falling back to UTF-16 otherwise. eglot 1.17+ advertises UTF-8, so JETLS picks UTF-8 when talking to it.
VS Code and Zed both handle the same UTF-8 positions correctly, which is consistent with this being a bug somewhere in eglot’s processing path rather than in the data JETLS sends.
You can verify this on your setup by forcing JETLS to use UTF-16. Set up a local JETLS checkout with this patch applied to JETLS:
diff --git a/src/initialize.jl b/src/initialize.jl
index 4ba882ae..022725cc 100644
--- a/src/initialize.jl
+++ b/src/initialize.jl
@@ -261,14 +261,15 @@ function handle_InitializeRequest(
end
end
- positionEncodings = getcapability(state, :general, :positionEncodings)
- if isnothing(positionEncodings) || isempty(positionEncodings)
- positionEncoding = PositionEncodingKind.UTF16
- elseif PositionEncodingKind.UTF8 in positionEncodings
- positionEncoding = PositionEncodingKind.UTF8
- else
- positionEncoding = first(positionEncodings)
- end
+ # positionEncodings = getcapability(state, :general, :positionEncodings)
+ # if isnothing(positionEncodings) || isempty(positionEncodings)
+ # positionEncoding = PositionEncodingKind.UTF16
+ # elseif PositionEncodingKind.UTF8 in positionEncodings
+ # positionEncoding = PositionEncodingKind.UTF8
+ # else
+ # positionEncoding = first(positionEncodings)
+ # end
+ positionEncoding = PositionEncodingKind.UTF16
state.encoding = positionEncoding
result = InitializeResult(;
If the error goes away, that confirms the issue lives on the eglot side, and we can take it upstream from there.
Those of you who know about the intricacies of the protocol should maybe comment there, I guess it is rare for languages to support Unicode natively so Julia may testing code paths that were previously unused.
@aviatesk, in the original issue you said that you cannot replicate, so there must be something different in your config compared to the MWE in the repo. If you could tell me what it is, I could use that as a workaround.
When I run your script using emacs 30.2, I do not encounter the error, only a minor warning from flymake. Perhaps noteworthy is that the eglot events buffer shows ∂ in the function name as three octal bytes rather than the unicode glyph.
Edit: I am using jetls version 2026-05-06.
I am using the straight setup from your MWE repo for this test. When I try it again today, I do encounter the indexing error when the cursor is over the function name on line 6; I don’t understand why I didn’t see it yesterday. Sorry for the noise if I simply didn’t test it correctly.
Anyway, you can obviate this particular error by adding :signatureHelpProvider to the eglot-ignored-server-capabilities variable (which is accessible from the emacs customization menu).
Also, “[jsonrpc] Could not start and/or connect” may just be a timeout problem. If so, you can manually re-invoke M-x eglot for the buffer, and jetls will restart more quickly (with cached library files, etc.)