All posts

Fix Infinite Loop in Clojure

Learn how to identify and fix infinite loops in Clojure applications, including common causes like unbounded recursion and lazy sequence pitfalls.

What Is an Infinite Loop in Clojure?

An infinite loop in Clojure typically occurs when a recursive function lacks a proper base case, or when lazy sequences are realized in a way that never terminates. Unlike imperative languages, Clojure's functional nature means loops often manifest as runaway recursion or infinite lazy sequences.

Why It Happens

The most frequent culprits are:

  • A loop/recur construct where the termination condition is never met
  • Calling (doall) or (vec) on an infinite lazy sequence
  • Mutually recursive functions that never bottom out

How to Fix It

Here's a classic example of an accidental infinite loop and its fix:

;; Broken — n never reaches 0 for negative inputs
(defn factorial [n]
  (loop [i n acc 1]
    (recur (dec i) (* acc i))))

;; Fixed — add a base case
(defn factorial [n]
  (loop [i n acc 1]
    (if (<= i 1)
      acc
      (recur (dec i) (* acc i)))))

For lazy sequences, always use take to bound them before realization:

;; Dangerous — will hang
(vec (iterate inc 0))

;; Safe
(vec (take 100 (iterate inc 0)))

Debugging Tips

Set a timeout on REPL evaluations during development. Add logging inside loop bodies to watch counter values. If you're using Bugsly for error monitoring, stack overflow exceptions from runaway recursion will surface with full stack traces, making it straightforward to pinpoint the offending function.

Always validate your inputs and ensure every recursive path has a reachable termination condition.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free