santiagocabrera96

santiagocabrera96

Programming Clojure, Fourth Edition: ex-info should include the cause. (p. 224)

In page 224, the following code is suggested.

(defn load-resource [path]
  (try
    (if (forbidden? path)
      (throw (ex-info "Forbidden resource"
                      {:status 403 :resource path}))
      (slurp path))
    (catch java.io.FileNotFoundException e
      (throw (ex-info "Missing resource"
                      {:status 404 :resource path})))
    (catch java.io.IOException e
      (throw (ex-info "Server error"
                      {:status 500 :resource path})))))

I’ve seen this in practice a lot and not including the cause when catching an exception generates headaches to debug later.

I’d suggest to do a bit of explanation of adding the cause exception to the ex info in the catch clauses like this:

(defn load-resource [path]
  (try
    (if (forbidden? path)
      (throw (ex-info "Forbidden resource"
                      {:status 403 :resource path}))
      (slurp path))
    (catch java.io.FileNotFoundException e
      (throw (ex-info "Missing resource"
                      {:status 404 :resource path}
                      e)))
    (catch java.io.IOException e
      (throw (ex-info "Server error"
                      {:status 500 :resource path}
                      e)))))

This is really useful for me to add context to exceptions that might happen in calling functions on sequences to understand what element failed.

Here’s a dummy example where I can call a function that might throw, and I would want more context on where it failed, and I can add context to the existing ex-info.

(defn randomly-fails []
  (when (> (rand-int 10) 8)
    (throw (ex-info "Randomly failed!" {}))))
(run! #(try (randomly-fails)
            (catch clojure.lang.ExceptionInfo e
              (throw (ex-info (ex-message e)
                              (assoc (ex-data e) :n %)
                              e))))
      (range 100))
=> #'examples.interop/randomly-fails
Execution error (ExceptionInfo) at examples.interop/randomly-fails (form-init16509100671821839256.clj:3).
Randomly failed!
*e
=>
#error
{:cause "Randomly failed!",
 :data {},
 :via [{:type clojure.lang.ExceptionInfo,
        :message "Randomly failed!",
        :data {:n 7},
        :at [examples.interop$eval2303$fn__2304 invoke "form-init16509100671821839256.clj" 6]}
       {:type clojure.lang.ExceptionInfo,
        :message "Randomly failed!",
        :data {},
        :at [examples.interop$randomly_fails invokeStatic "form-init16509100671821839256.clj" 3]}],

Where Next?

Popular Pragmatic Bookshelf topics Top

jesse050717
Title: Web Development with Clojure, Third Edition, pg 116 Hi - I just started chapter 5 and I am stuck on page 116 while trying to star...
New
gilesdotcodes
In case this helps anyone, I’ve had issues setting up the rails source code. Here were the solutions: In Gemfile, change gem 'rails' t...
New
New
hgkjshegfskef
The test is as follows: Scenario: Intersecting a scaled sphere with a ray Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) And s ← sphere...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
Henrai
Hi, I’m working on the Chapter 8 of the book. After I add add the point_offset, I’m still able to see acne: In the image above, I re...
New
a.zampa
@mfazio23 I’m following the indications of the book and arriver ad chapter 10, but the app cannot be compiled due to an error in the Bas...
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New
davetron5000
Hello faithful readers! If you have tried to follow along in the book, you are asked to start up the dev environment via dx/build and ar...
New
dachristenson
I’ve got to the end of Ch. 11, and the app runs, with all tabs displaying what they should – at first. After switching around between St...
New

Other popular topics Top

PragmaticBookshelf
Brace yourself for a fun challenge: build a photorealistic 3D renderer from scratch! In just a couple of weeks, build a ray tracer that r...
New
PragmaticBookshelf
Learn from the award-winning programming series that inspired the Elixir language, and go on a step-by-step journey through the most impo...
New
DevotionGeo
I know that these benchmarks might not be the exact picture of real-world scenario, but still I expect a Rust web framework performing a ...
New
New
AstonJ
We’ve talked about his book briefly here but it is quickly becoming obsolete - so he’s decided to create a series of 7 podcasts, the firs...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
New
sir.laksmana_wenk
I’m able to do the “artistic” part of game-development; character designing/modeling, music, environment modeling, etc. However, I don’t...
New
PragmaticBookshelf
As digital systems increasingly run the world, mastery of the recurring patterns of software development risk is the key to fast and effe...
New
xiji2646-netizen
Woke up to this today: Claude Code’s complete source code exposed via npm source map. Not a snippet. All 512,000 lines. 1,900 TypeScript ...
New

Sub Categories: