cider icon indicating copy to clipboard operation
cider copied to clipboard

`cider-stacktrace-render` works incorrectly for ClojureScript

Open rrudakov opened this issue 7 months ago • 1 comments

Expected behavior

When I eval a ClojureScript expression that causes an exception, *cider-error* buffer is displayed with the exception data.

Actual behavior

The *cider-error* buffer contains only the following text:


  Show: Project-Only All 
  Hide: Clojure Java REPL Tooling Duplicates  (0 frames hidden)

and the following error is signaled:

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  propertize(nil font-lock-face cider-stacktrace-error-class-face mouse-face highlight)
  (insert (format "%d. " num) (propertize note 'font-lock-face 'font-lock-comment-face) " " (propertize class 'font-lock-face class-face 'mouse-face 'highlight) "\n")
  (progn (insert (format "%d. " num) (propertize note 'font-lock-face 'font-lock-comment-face) " " (propertize class 'font-lock-face class-face 'mouse-face 'highlight) "\n"))
  (prog1 (progn (insert (format "%d. " num) (propertize note 'font-lock-face 'font-lock-comment-face) " " (propertize class 'font-lock-face class-face 'mouse-face 'highlight) "\n")) (add-text-properties start (point) (list 'detail 0 'inspect-index inspect-index 'keymap cider-stacktrace-exception-map)))
  (let ((start (point))) (prog1 (progn (insert (format "%d. " num) (propertize note 'font-lock-face 'font-lock-comment-face) " " (propertize class 'font-lock-face class-face 'mouse-face 'highlight) "\n")) (add-text-properties start (point) (list 'detail 0 'inspect-index inspect-index 'keymap cider-stacktrace-exception-map))))
  (progn (let ((start (point))) (prog1 (progn (insert (format "%d. " num) (propertize note 'font-lock-face 'font-lock-comment-face) " " (propertize class 'font-lock-face class-face 'mouse-face 'highlight) "\n")) (add-text-properties start (point) (list 'detail 0 'inspect-index inspect-index 'keymap cider-stacktrace-exception-map)))) (let ((start (point))) (prog1 (progn (if (equal class "clojure.lang.Compiler$CompilerException") (cider-stacktrace-render-compile-error buffer cause) (cider-stacktrace-emit-indented (propertize (or message "(No message)") 'font-lock-face message-face) indent t)) (if triage (progn (insert "\n") (cider-stacktrace-emit-indented (propertize ... ... message-face) indent nil))) (if spec (progn (insert "\n") (cider-stacktrace--emit-spec-problems spec (concat indent "  ")))) (if data (progn (insert "\n") (let (...) (prog1 ... ...)))) (insert "\n")) (add-text-properties start (point) '(detail 1)))) (let ((start (point))) (prog1 (progn (let ((beg (point)) (bg (cons ... ...))) (let ((tail stacktrace)) (while tail (let ... ... ... ...))) (overlay-put (make-overlay beg (point)) 'font-lock-face bg))) (add-text-properties start (point) '(detail 2)))) (let ((start (point))) (prog1 (progn (insert "\n")) (add-text-properties start (point) '(detail 0)))))
  (prog1 (progn (let ((start (point))) (prog1 (progn (insert (format "%d. " num) (propertize note 'font-lock-face 'font-lock-comment-face) " " (propertize class 'font-lock-face class-face 'mouse-face 'highlight) "\n")) (add-text-properties start (point) (list 'detail 0 'inspect-index inspect-index 'keymap cider-stacktrace-exception-map)))) (let ((start (point))) (prog1 (progn (if (equal class "clojure.lang.Compiler$CompilerException") (cider-stacktrace-render-compile-error buffer cause) (cider-stacktrace-emit-indented (propertize ... ... message-face) indent t)) (if triage (progn (insert "\n") (cider-stacktrace-emit-indented ... indent nil))) (if spec (progn (insert "\n") (cider-stacktrace--emit-spec-problems spec ...))) (if data (progn (insert "\n") (let ... ...))) (insert "\n")) (add-text-properties start (point) '(detail 1)))) (let ((start (point))) (prog1 (progn (let ((beg ...) (bg ...)) (let (...) (while tail ...)) (overlay-put (make-overlay beg ...) 'font-lock-face bg))) (add-text-properties start (point) '(detail 2)))) (let ((start (point))) (prog1 (progn (insert "\n")) (add-text-properties start (point) '(detail 0))))) (add-text-properties start (point) (list 'cause num)))
  (let ((start (point))) (prog1 (progn (let ((start (point))) (prog1 (progn (insert (format "%d. " num) (propertize note ... ...) " " (propertize class ... class-face ... ...) "\n")) (add-text-properties start (point) (list 'detail 0 'inspect-index inspect-index 'keymap cider-stacktrace-exception-map)))) (let ((start (point))) (prog1 (progn (if (equal class "clojure.lang.Compiler$CompilerException") (cider-stacktrace-render-compile-error buffer cause) (cider-stacktrace-emit-indented ... indent t)) (if triage (progn ... ...)) (if spec (progn ... ...)) (if data (progn ... ...)) (insert "\n")) (add-text-properties start (point) '(detail 1)))) (let ((start (point))) (prog1 (progn (let (... ...) (let ... ...) (overlay-put ... ... bg))) (add-text-properties start (point) '(detail 2)))) (let ((start (point))) (prog1 (progn (insert "\n")) (add-text-properties start (point) '(detail 0))))) (add-text-properties start (point) (list 'cause num))))
  (let ((indent "   ") (class-face 'cider-stacktrace-error-class-face) (message-face 'cider-stacktrace-error-message-face)) (let ((start (point))) (prog1 (progn (let ((start (point))) (prog1 (progn (insert ... ... " " ... "\n")) (add-text-properties start (point) (list ... 0 ... inspect-index ... cider-stacktrace-exception-map)))) (let ((start (point))) (prog1 (progn (if ... ... ...) (if triage ...) (if spec ...) (if data ...) (insert "\n")) (add-text-properties start (point) '...))) (let ((start (point))) (prog1 (progn (let ... ... ...)) (add-text-properties start (point) '...))) (let ((start (point))) (prog1 (progn (insert "\n")) (add-text-properties start (point) '...)))) (add-text-properties start (point) (list 'cause num)))))
  (let ((class (nrepl-dict-get cause "class")) (message (nrepl-dict-get cause "message")) (data (nrepl-dict-get cause "data")) (spec (nrepl-dict-get cause "spec")) (triage (nrepl-dict-get cause "triage")) (stacktrace (nrepl-dict-get cause "stacktrace"))) (let ((indent "   ") (class-face 'cider-stacktrace-error-class-face) (message-face 'cider-stacktrace-error-message-face)) (let ((start (point))) (prog1 (progn (let ((start ...)) (prog1 (progn ...) (add-text-properties start ... ...))) (let ((start ...)) (prog1 (progn ... ... ... ... ...) (add-text-properties start ... ...))) (let ((start ...)) (prog1 (progn ...) (add-text-properties start ... ...))) (let ((start ...)) (prog1 (progn ...) (add-text-properties start ... ...)))) (add-text-properties start (point) (list 'cause num))))))
  (save-current-buffer (set-buffer buffer) (let ((class (nrepl-dict-get cause "class")) (message (nrepl-dict-get cause "message")) (data (nrepl-dict-get cause "data")) (spec (nrepl-dict-get cause "spec")) (triage (nrepl-dict-get cause "triage")) (stacktrace (nrepl-dict-get cause "stacktrace"))) (let ((indent "   ") (class-face 'cider-stacktrace-error-class-face) (message-face 'cider-stacktrace-error-message-face)) (let ((start (point))) (prog1 (progn (let (...) (prog1 ... ...)) (let (...) (prog1 ... ...)) (let (...) (prog1 ... ...)) (let (...) (prog1 ... ...))) (add-text-properties start (point) (list 'cause num)))))))
  cider-stacktrace-render-cause(#<buffer *cider-error*> (dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error")) 1 "Unhandled" 0)
  (let ((note (if (= num causes-length) "Unhandled" "Caused by"))) (cider-stacktrace-render-cause buffer cause num note (- causes-length num)) (setq num (1- num)))
  (let ((cause (car tail))) (let ((note (if (= num causes-length) "Unhandled" "Caused by"))) (cider-stacktrace-render-cause buffer cause num note (- causes-length num)) (setq num (1- num))) (setq tail (cdr tail)))
  (while tail (let ((cause (car tail))) (let ((note (if (= num causes-length) "Unhandled" "Caused by"))) (cider-stacktrace-render-cause buffer cause num note (- causes-length num)) (setq num (1- num))) (setq tail (cdr tail))))
  (let ((tail causes)) (while tail (let ((cause (car tail))) (let ((note (if (= num causes-length) "Unhandled" "Caused by"))) (cider-stacktrace-render-cause buffer cause num note (- causes-length num)) (setq num (1- num))) (setq tail (cdr tail)))))
  (let* ((causes-length (length causes)) (num causes-length)) (let ((tail causes)) (while tail (let ((cause (car tail))) (let ((note (if ... "Unhandled" "Caused by"))) (cider-stacktrace-render-cause buffer cause num note (- causes-length num)) (setq num (1- num))) (setq tail (cdr tail))))))
  (let ((inhibit-read-only t)) (erase-buffer) (insert "\n") (cider-stacktrace-render-filters buffer '(("Project-Only" project) ("All" all)) '(("Clojure" clj) ("Java" java) ("REPL" repl) ("Tooling" tooling) ("Duplicates" dup))) (insert "\n") (if error-types (progn (cider-stacktrace-render-suppression-toggle buffer error-types) (insert "\n\n"))) (let* ((causes-length (length causes)) (num causes-length)) (let ((tail causes)) (while tail (let ((cause (car tail))) (let ((note ...)) (cider-stacktrace-render-cause buffer cause num note (- causes-length num)) (setq num (1- num))) (setq tail (cdr tail)))))))
  (save-current-buffer (set-buffer buffer) (let ((inhibit-read-only t)) (erase-buffer) (insert "\n") (cider-stacktrace-render-filters buffer '(("Project-Only" project) ("All" all)) '(("Clojure" clj) ("Java" java) ("REPL" repl) ("Tooling" tooling) ("Duplicates" dup))) (insert "\n") (if error-types (progn (cider-stacktrace-render-suppression-toggle buffer error-types) (insert "\n\n"))) (let* ((causes-length (length causes)) (num causes-length)) (let ((tail causes)) (while tail (let ((cause ...)) (let (...) (cider-stacktrace-render-cause buffer cause num note ...) (setq num ...)) (setq tail (cdr tail))))))) (cider-stacktrace-initialize causes) (font-lock-refresh-defaults))
  cider-stacktrace-render(#<buffer *cider-error*> ((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error"))) nil)
  (let* ((repl (or repl (cider-current-repl))) (error-buffer (cider-new-error-buffer #'cider-stacktrace-mode error-types is-compilation))) (save-current-buffer (set-buffer error-buffer) (setq cider--ancillary-buffer-repl repl)) (cider-stacktrace-render error-buffer causes error-types))
  (progn (let* ((repl (or repl (cider-current-repl))) (error-buffer (cider-new-error-buffer #'cider-stacktrace-mode error-types is-compilation))) (save-current-buffer (set-buffer error-buffer) (setq cider--ancillary-buffer-repl repl)) (cider-stacktrace-render error-buffer causes error-types)))
  (if causes (progn (let* ((repl (or repl (cider-current-repl))) (error-buffer (cider-new-error-buffer #'cider-stacktrace-mode error-types is-compilation))) (save-current-buffer (set-buffer error-buffer) (setq cider--ancillary-buffer-repl repl)) (cider-stacktrace-render error-buffer causes error-types))))
  cider--render-stacktrace-causes(((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error"))) nil nil #<buffer *cider-repl Projects/cljs-tutorial:localhost:61718(cljs:browser)*>)
  cider--handle-stacktrace-response(((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error"))) nil #<buffer *cider-repl Projects/cljs-tutorial:localhost:61718(cljs:browser)*>)
  #f(lambda (causes phase) [(buffer #<buffer *cider-repl Projects/cljs-tutorial:localhost:61718(cljs:browser)*>)] (cider--handle-stacktrace-response causes phase buffer))(((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error"))) nil)
  funcall(#f(lambda (causes phase) [(buffer #<buffer *cider-repl Projects/cljs-tutorial:localhost:61718(cljs:browser)*>)] (cider--handle-stacktrace-response causes phase buffer)) ((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error"))) nil)
  (if (member "done" status) (funcall callback causes ex-phase) (if phase (progn (setq ex-phase phase))) (setq causes (append causes (list response))))
  (let ((status (nrepl-dict-get response "status")) (phase (nrepl-dict-get response "phase"))) (if (member "done" status) (funcall callback causes ex-phase) (if phase (progn (setq ex-phase phase))) (setq causes (append causes (list response)))))
  #f(lambda (response) [(ex-phase nil) (causes ((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("no-error")))) (callback #f(lambda (causes phase) [(buffer #<buffer *cider-repl Projects/cljs-tutorial:localhost:61718(cljs:browser)*>)] (cider--handle-stacktrace-response causes phase buffer)))] (let ((status (nrepl-dict-get response "status")) (phase (nrepl-dict-get response "phase"))) (if (member "done" status) (funcall callback causes ex-phase) (if phase (progn (setq ex-phase phase))) (setq causes (append causes (list response))))))((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("done")))
  nrepl--dispatch-response((dict "id" "134" "session" "4a471f61-529b-4398-aa85-59891c1c8fde" "status" ("done")))
  nrepl-client-filter(#<process nrepl-connection> "d2:id3:1347:session36:4a471f61-529b-4398-aa85-59891c1c8fde6:statusl8:no-erroreed2:id3:1347:session36:4a471f61-529b-4398-aa85-59891c1c8fde6:statusl4:doneee")

Steps to reproduce the problem

  1. Create a simple hello world ClojureScript project from the quick start tutorial.
  2. Evaluate any form that throws an exception either in the REPL buffer or in the source buffer. For example:
(throw (ex-info "Error" {:some "Data"}))

;; or

(ffirst [1])

Notes after some debugging

  1. The error is signaled from the cider-stacktrace-render-cause function, because class is nil in the expression (propertize class 'font-lock-face class-face 'mouse-face 'highlight).
  2. I tried to comment the problematic expression, the error is gone but the *cider-error* buffer shows not very useful information:
Image

Environment & Version information

CIDER version information

;; CIDER 1.18.0 (Athens), nREPL 1.3.1
;; Clojure 1.12.0, Java 23.0.2

Lein / Clojure CLI version

Clojure CLI 1.12

Emacs version

GNU Emacs 31.0.50 (build 1, aarch64-apple-darwin24.4.0, NS appkit-2575.50 Version 15.4.1 (Build 24E263)) of 2025-04-29

Operating system

MacOS

JDK distribution

openjdk version "23.0.2" 2025-01-21 OpenJDK Runtime Environment Homebrew (build 23.0.2) OpenJDK 64-Bit Server VM Homebrew (build 23.0.2, mixed mode, sharing)

rrudakov avatar May 17 '25 07:05 rrudakov

Hmm, seems like some weird regression as the stacktrace middlware doesn't support ClojureScript at all and this window should not be triggered for ClojureScript errors.

bbatsov avatar May 24 '25 08:05 bbatsov