-
Notifications
You must be signed in to change notification settings - Fork 34
Error Handling
Maria provides a safe playground for experimentation. Therefore, errors of all sorts must be caught and translated into humane, beginner-friendly language. These errors should be worded gently and should suggest ways to solve the error.
Those interested in how Maria wraps errors should read src/maria/messages.cljs and related namespaces. π€ ππΎ
When it comes to the fight against opaque error messages, we are stronger together. πͺπΎ Please feel free to add to this list!
Consider (let [a/b 1] a/b)
(gist). The response is:
Invalid local name: a/b at line 1
Compile error: we were unable to turn this code into JavaScript. π°
...and then a huge dump describing the compilation error. Perhaps the compilation error should by default be hidden, and expand only on click? Ideally we would surface a friendly rephrasing of "Invalid local name" (which is now hidden)
we could catch things like (defun subtract [a b] (- a b))
and say, "Hey friend, maybe you meant defn
?" and then everybody gets to define functions to their heart's content
this is not the right message for this scenario
If the developer accidentally puts the docstring after the arglist, it gets treated as any other expression that's part of the function body, and the attempted docstring is instead dropped on the floor. That's a bummer! Maybe we should warn folks when they put a string between the arglist and the expressions.
E.g. this has no docstring, despite the obvious intent
(defn add [a b] "A function that adds a with b." (+ a b))
because it needs to go before the arglist:
(defn add "A function that adds a with b." [a b] (+ a b))
Expected forms:
(defn name doc-string? attr-map? [params*] prepost-map? body)
(defn name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?)
(_ layer)
evaluates to ##NaN
-- this doesn't seem to be an error, but it's a failure condition we should consider.
no error message--no warning--nothing in console? I'm feeling like I took crazy pills.
on
(map nil [1 2 3])
Need to investigate scenarios where this could occur naturally. Perhaps best "Expected a function but found nil
"
Trying to name a var using an emoji causes "illegal character":
(def keysπ ["π" "πΉ" "π"])
> illegal character
See #170 https://github.com/mhuebert/maria/issues/170
Should be fixed by c192db9
(circle "puppy")
radius must be a number!
Ideally we'd say more here, and use syntax highlighting. Maybe something like
Argument
radius
has to be a number. The functioncircle
can't use"puppy"
because it is a string.
This should be fixed at the source, in shapes' circle
and assert-number
definitions. If at all possible, throw more than a bare js/Error
.
expressions with single-quoted terms, like (circle 'hello')
slip through undeclared-var
detection and result in "invalid is too many arguments!"
- M: looks like
'
is a valid character inside a symbol, so errors will be unpredictable -- caused by passing a symbol where something else is expected. We could try and generate a warning whenever a symbol ends in'
(maybe we can do this check in themagic-tree
read or emit phase, otherwise we have to traverse every form). Or combine better overall argument validation (eg. more clojure.spec) with a hook at the end which checks invalid args for patterns like this.
(inc dec)
causes ""function cljs$core$dec(x){\nreturn (x - (1));\n}1""
- M: no runtime validation of args. maybe using clojure.spec with instrument can help - added #71.
(map [1 2 3] inc)
causes console error πΏ, no result πΏ, and a broken environment. π©!
- M: lazy seqs... we should be catching errors in
format-value
, and pass them to our error code, as lazy seqs do not realize until rendered, and even then only one slice at a time. Added #70.
(:a "B")
causes "nil" output, even though we'd like to detect attempted use of key lookups on non-maps and suggest alternatives. See https://github.com/yogthos/clojure-error-message-catalog/blob/master/clj/wrong-num-args-passed-to-keyword.md
Similarly, (:first-name "Bob", :last-name "Bobberton")
causes "(intermediate value).cljs$core$IFn$_invoke$arity$3 is not a function\n\nThe function first-name
in the expression above needs a different number of arguments.""
(defn destructure-fn [[a b] num] a)
then (destructure-fn 3 [1 2])
causes "nth not supported on this type function Number() { [native code] }"
We should catch the attempt to destructure and point to it as a possible cause when this error occurs. See https://github.com/yogthos/clojure-error-message-catalog/blob/master/clj/nth-not-supported-on-this-type.md
- M: not sure if we can make sense of this without moving down the stack and showing the location in the destructuring form where the mismatch is occurring. In general, traversing the stack with source lookup and location underline would be a nice thing to have.
See https://github.com/yogthos/clojure-error-message-catalog/blob/master/cljs/duplicate-case-test-constant.md for an overview of the error.
We currently catch and reword the initial error, but that is only one-third of the total error message. We still are getting an unwanted follow-up looking like:
Duplicate case test constant '1' on line 1 at line 1
Error: Duplicate case test constant '1' on line 1 at line 1
at new cljs$core$ExceptionInfo (http://localhost:3449/js/compiled/out-user-dev/cljs/core.js:35636:10)
at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (http://localhost:3449/js/compiled/out-user-dev/cljs/core.js:35712:9)
at cljs$core$ex_info (http://localhost:3449/js/compiled/out-user-dev/cljs/core.js:35698:26)
at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:1073:26)
at cljs$analyzer$error (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:1059:28)
at cljs$analyzer$macroexpand_1 (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:5291:27)
at Function.cljs.analyzer.analyze_seq.cljs$core$IFn$_invoke$arity$4 (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:5365:41)
at cljs$analyzer$analyze_seq (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:5337:34)
at cljs$analyzer$analyze_form (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:5508:34)
at cljs$analyzer$analyze_STAR_ (http://localhost:3449/js/compiled/out-user-dev/cljs/analyzer.js:5549:38)
{:type :overload-arity, :extra {:name twice}}
We misreport the cause of this. See https://github.com/yogthos/clojure-error-message-catalog/blob/master/clj/let-requires-even-number-forms.md
- M: looks like all "Could not compile" errors are currently interpreted as 'It looks like you're declaring a function' which is getting in the way.
(nth '(1 2 3) 20)
((circle 20))
reported by Jakub Holy in #206