Clojure-LSP doesn't start anymore with 2025.06.13-20.45.44
As of Monday 16th June I cannot start the clojure-lsp through calva for my work repository (it works in a new repository I created this morning).
I attached what I could diagnose so far but it is fuzzy, I will gladly provide more context if you can guide me to what would help.
On the left my work project (the one failing), and on the right the new repository I created this morning which works.
The left one doesn't start because of an internal error (I couldn't find helpful log to diagnose why the server doesn't start), only thing I get is Internal Error [Object object]. No issues on the right. The terminal is in the calva extension folder and you can see the version it is currently running.
I then changed the version of the clojure-lsp in my vscode config to: "calva.clojureLspVersion": "2025.06.06-19.04.49", I then ran the vscode command: Calva Clojure LSP: Download the configured Clojure LSP Server version.
Now both of my projects start:
Hi! Thanks for reporting!
Calva has a some clojure-lsp diagnostics, but I wonder if those help when the server crashes that early. You could try to click the clojure-lsp button in the status bar and see if you can even reach the diagnostics. By default, the clojure-lsp log is in /tmp/clojure-lsp.out.
My guess is that there is something wrong with latest clojure-lsp that is exposed by your work project. You could try to download the clojure-lsp binary for your system from https://github.com/clojure-lsp/clojure-lsp/releases and then run /path/to/clojure-lsp diagnostics --verbose from the root of your project.
@ericdallo: Do you have any suggestions for how to diagnose the problem?
Regarding the clojure-lsp button, I get nothing, since the server doesn't start and the client cannot connect the only option available is Start.
I did try the latest binary directly, on my working project I get some results when I had an unused require. For my working project nothing comes up (assuming this is the data exposed under the Problems tab in VSCode) there should be.
I skipped the classpath for now, here is the output with the --verbose flag:
[ 20%] Copying kondo configs [WARN] [clj-kondo] Configs copied:
- .clj-kondo/com.github.seancorfield/next.jdbc
- .clj-kondo/funcool/cats
- .clj-kondo/http-kit/http-kit
- .clj-kondo/nubank/matcher-combinators
- .clj-kondo/nubank/state-flow
- .clj-kondo/potemkin/potemkin
- .clj-kondo/taoensso/encore
[INFO] :internal/copy-kondo-configs 774ms
[ 25%] Analyzing external classpath[INFO] [startup] Analyzing classpath for project root /Users/mathieu/Programming/eleven/meta-monorepo/runeleven
[INFO] [clj-kondo] Analyzing 297 paths with clj-kondo in 3 batches...
[INFO] [clj-kondo] Analyzing batch 1/3
[ 31%] Analyzing external classpathConfigs copied:
- .clj-kondo/http-kit/http-kit
- .clj-kondo/nubank/matcher-combinators
- .clj-kondo/nubank/state-flow
[INFO] :internal/kondo-findings->analysis 0ms
[INFO] [clj-kondo] Analyzing batch 2/3
[ 37%] Analyzing external classpathConfigs copied:
- .clj-kondo/com.github.seancorfield/next.jdbc
- .clj-kondo/potemkin/potemkin
- .clj-kondo/taoensso/encore
[INFO] :internal/kondo-findings->analysis 0ms
[INFO] [clj-kondo] Analyzing batch 3/3
[ 44%] Analyzing external classpathConfigs copied:
- .clj-kondo/funcool/cats
[INFO] :internal/kondo-findings->analysis 0ms
[INFO] :internal/external-classpath-analysis 7633ms
[INFO] :internal/maintain-dep-graph 36ms
[INFO] :internal/manual-gc-after-classpath-scan 279ms
[INFO] [startup] Caching db for next startup...
[INFO] :db/manual-gc-before-update-db 263ms
[INFO] :db/upsert-cache 294ms
[ 45%] Resolving config paths [INFO] :internal/find-classpath-configs 29ms
[ 50%] Analyzing project files [INFO] [startup] Analyzing source paths for project root /Users/mathieu/Programming/eleven/meta-monorepo/runeleven
[INFO] :internal/project-paths-analyzed-by-clj-depend 0ms
[ 98%] Analyzing project files No configs copied.
[INFO] :internal/kondo-findings->analysis 0ms
[INFO] :internal/project-paths-analyzed-by-clj-kondo 15688ms
[INFO] :internal/maintain-dep-graph 18ms
Managed to find some more logs using the path from the working version, maybe I have some older settings but for me they are located under /var/folders/**/
I can see an exception (Invalid character: ` found while reading keyword.) being thrown in the following log file:
Oh interesting case, from the logs, it seems there is some file with a backtick in the keyword, maybe something like :foo`, never saw something like that, could you check your code or manage to make a public repro so I can try?
Even so we should not crash server, but I need to understand better the case to avoid that in the future
With a quick search, I only saw this kind of patterns in my javadoc, nothing in the code. Do you think it can be relevant?
An example of javadoc would be:
"Add :from/:join/:where to a query for a denormalized set of account-lines
By default filters on ledger-status=posted accepts options
- `:account-type`
- `:account-subtype`
- `:ledger-status`
- `:journal-entry-status`"
I can't open this repository, I'll try to fiddle with the LSP and see what more info I can get.
Looking at the diff between the two releases (https://github.com/clojure-lsp/clojure-lsp/compare/2025.06.06-19.04.49...2025.06.13-20.45.44) the implementation of lib/src/clojure_lsp/parser.clj/zloc-of-file has changed:
From the stack trace this is where the issue seems to be coming from:
clojure-lsp.parser/zloc-of-file parser.clj: 110
clojure-lsp.parser/zloc-of-string parser.clj: 96
clojure-lsp.parser/z-of-string* parser.clj: 46
So most likely the issue is somewhat related to the introduction of (shared/slurp-uri uri).
I'll find some time this week to fork the LSP and fiddle with this, hopefully catching the exception to get the URI would narrow the search. From there we'll see what's possible, I may be able to open a single file for further analysis.
Yes, your finding is correct, the point is that we fixed a place we should have been doing that, the problem here is that the clojure file we are trying to parse with rewrite-clj is wrong, if that javadoc is from a clojure file, it may be related, yes
Wrapped zloc-of-string in a try/catch and managed to get the exception with the URI of the faulty file. The issue had nothing to do with the javadoc; the same file had javadoc inside the function with the same pattern I copied earlier.
The culprit was a typo in some hiccup:
[:table` ...]
; instead of
[:table ...]
I saw the following piece of code:
(defn ^:private zloc-of-string [text]
(try
(z-of-string* text)
(catch clojure.lang.ExceptionInfo e
(or (handle-end-slash-code text e)
(handle-keyword-with-end-slash-code text e)
(handle-single-colon-code text e)
(throw e)))))
Maybe we could change (handle-keyword-with-end-slash-code text e) to be a bit more generic in how it deals with invalid keywords?
(comment
(zloc-of-string "[:table/]")
;;=> [{:children
;; ({:tag :vector,
;; :format-string "[%s]",
;; :wrap-length 2,
;; :seq-fn #function[clojure.core/vec],
;; :children ({:k :table/, :auto-resolved? false, :map-qualifier nil})})}
;; nil]
(zloc-of-string "[:table`]")
;;=> Execution error (ExceptionInfo) at clojure.tools.reader.impl.errors/throw-ex (errors.clj:34).
;; [line 1, col 9] Invalid character: ` found while reading keyword.
;;
:rcf)
good debugging! I think so @mathieuroblin, but not sure this should be fixed in rewrite-clj, not sure if this is clojure invalid c/c @lread
We do have a rewrite-clj issue for parsing invalid code: https://github.com/clj-commons/rewrite-clj/issues/87
In that case, maybe we could just wrap the exception to give a bit more context? I was thinking something like this:
; Wrapped exception for context in the implementation since multiple caller rely on this.
(defn zloc-of-file [db uri]
(let [text (or (get-in db [:documents uri :text])
(shared/slurp-uri uri))]
(try
(zloc-of-string text)
(catch clojure.lang.ExceptionInfo e
(throw (ex-info "Failed to parse file"
(into (ex-data e) {:uri uri :text text})
e))))))
; Then, use said context in the `safe-` wrapper to maybe replace `file` by the path in the logger?
(defn safe-zloc-of-file [db uri]
(try
(zloc-of-file db uri)
(catch Exception _e
(logger/warn "It was not possible to parse file. Probably not valid clojure code."))))
@mathieuroblin Hum, I think it's a start