Skip to content

cider-stacktrace-render works incorrectly for ClojureScript #3821

Open
@rrudakov

Description

@rrudakov

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions