Failjure [](https://github.com/clj-commons/failjure/actions/workflows/test-and-release.yml) [](https://github.com/clj-commons/failjure/actions/workflows/test-and-snapshot.yml) [](https://github.com/clj-commons/failjure/actions/workflows/test.yml)

August 6, 2026 ยท View on GitHub

Failjure is a utility library for working with failed computations in Clojure(Script). It provides an alternative to exception-based error handling for applications where functional purity is more important.

It was inspired by Andrew Brehaut's error monad implementation.

Installation

Clojars cljdoc

Add the following to your build dependencies:

deps.edn:

    failjure/failjure {:mvn/version "2.3.0"}

Leiningen:

    [failjure/failjure "2.3.0"]

You can also include the specs via the failjure-spec project, if you're into that sort of thing:

Clojars Project

Failjure works on Clojure 1.10 and above, ClojureScript 1.11 and above, and Babashka (tested against v1.13.* but should work on v1.12.*).

Note: the tests pass for Clojure 1.8 and 1.9 but those are not officially supported here.

Example


(require '[failjure.core :as f])

;; Write functions that return failures
(defn validate-email [email]
    (if (re-matches #".+@.+\..+" email)
      email
      (f/fail "Please enter a valid email address (got %s)" email)))

(defn validate-not-empty [s]
  (if (empty? s)
    (f/fail "Please enter a value")
    s))

;; Use attempt-all to handle failures
(defn validate-data [data]
  (f/attempt-all [email (validate-email (:email data))
                  username (validate-not-empty (:username data))
                  id (f/try* (Integer/parseInt (:id data)))]
    {:email email
     :username username}
    (f/when-failed [e]
      (log-error (f/message e))
      (handle-error e))))

Quick Reference

HasFailed

The cornerstone of this library, HasFailed is the protocol that describes a failed result. Failjure implements HasFailed for Object (the catch-all not-failed implementation), Exception, and the built-in Failure record type, but you can add your own very easily:

(defrecord AnnotatedFailure [message data]
  f/HasFailed
  (failed? [self] true)
  (message [self] (:message self)))

fail

fail is the basis of this library. It accepts an error message with optional formatting arguments (formatted with Clojure's format function) and creates a Failure object.

(f/fail "Message here") ; => #Failure{:message "Message here"}
(f/fail "Hello, %s" "Failjure") ; => #Failure{:message "Hello, Failjure"}

failed? and message

These two functions are part of the HasFailed protocol underpinning failjure. failed? will tell you if a value is a failure (that is, a Failure, a java Exception or a JavaScript Error.

attempt

Added in 2.1

Accepts a value and a function. If the value is a failure, it is passed to the function and the result is returned. Otherwise, value is returned.

(defn handle-error [e] (str "Error: " (f/message e)))
(f/attempt handle-error "Ok")  ;=> "Ok"
(f/attempt handle-error (f/fail "failure"))  ;=> "Error: failure"

Try it with partial!

attempt-all

attempt-all wraps an error monad for easy use with failure-returning functions. You can add any number of bindings and it will short-circuit on the first error, returning the failure.

(f/attempt-all [x "Ok"] x)  ; => "Ok"
(f/attempt-all [x "Ok"
              y (fail "Fail")] x) ; => #Failure{:message "Fail"}

You can use when-failed to provide a function that will handle an error:

(f/attempt-all [x "Ok"
                y (fail "Fail")]
  x
  (f/when-failed [e]
    (f/message e))) ; => "Fail"

ok-> and ok->>

If you're on-the-ball enough that you can represent your problem as a series of compositions, you can use these threading macros instead. Each form is applied to the output of the previous as in -> and ->> (or, more accurately, some-> and some->>), except that a failure value is short-circuited and returned immediately.

Previous versions of failjure used attempt-> and attempt->>, which do not short-circuit if the starting value is a failure. ok-> and ok->> correct this shortcoming


(defn validate-non-blank [data field]
  (if (empty? (get data field))
    (f/fail "Value required for %s" field)
    data))

(let [result (f/ok->
              data
              (validate-non-blank :username)
              (validate-non-blank :password)
              (save-data))]
  (when (f/failed? result)
    (log (f/message result))
    (handle-failure result)))

as-ok->

Added in 2.1

Like clojure's built-in as->, but short-circuits on failures.


(f/as-ok-> "k" $
  (str $ "!")
  (str "O" $))) ; => Ok!

(f/as-ok-> "k" $
  (str $ "!")
  (f/try* (Integer/parseInt $))
  (str "O" $))) ; => Returns (does not throw) a NumberFormatException

try*

This library does not handle exceptions by default. However, you can wrap any form or forms in the try* macro, which is shorthand for:

(try
  (do whatever)
  (catch Exception e e))

Since failjure treats returned exceptions as failures, this can be used to adapt exception-throwing functions to failjure-style workflows.

try-all

A version of attempt-all which automatically wraps each right side of its bindings in a try* is available as try-all (thanks @lispyclouds):

(try-all [x (/ 1 0)
          y (* 2 3)]
  y)  ; => java.lang.ArithmeticException (returned, not thrown)

(if-|when-)-let-(ok?|failed?)

Failjure provides the helpers if-let-ok?, if-let-failed?, when-let-ok? and when-let-failed? to help with branching. Each has the same basic structure:

(f/if-let-failed? [x (something-which-may-fail)]
  (handle-failure x)
  (handle-success x))
  • If no else is provided, the if- variants will return the value of x
  • The when- variants will always return the value of x

assert-with

The assert-with helper is a very basic way of adapting non-failjure-aware functions/values to a failure context. The source is simply:

(defn assert-with
  "If (pred v) is true, return v
   otherwise, return (f/fail msg)"
  [pred v msg]
  (if (pred v) v (fail msg)))

The usage looks like this:

(f/attempt-all
  [x (f/assert-with some? (some-fn) "some-fn failed!")
   y (f/assert-with integer? (some-integer-returning-fn) "Not an integer.")]
  (handle-success x)
  (f/when-failed [e] (handle-failure e)))

The pre-packaged helpers assert-some?, assert-nil?, assert-not-nil?, assert-not-empty?, and assert-number? are provided, but if you like, adding your own is as easy as (def assert-my-pred? (partial f/assert-with my-pred?)).

License

Copyright (c) 2016-2026 Adam Bard and Andrew Brehaut

Distributed under the Eclipse Public License v1.0 (same as Clojure).