clojure/clojure · error · RuntimeException

EOF while reading, starting at line

Error message

EOF while reading, starting at line {}

What it means

Same condition as "EOF while reading" — input ended while a form or delimited list was still open — but the reader knows the line where the form began (firstline >= 0), so the exception includes that line to help locate the truncation.

Solutions

  1. Go to the reported starting line and balance the delimiters from there
  2. Use a paren-matching editor/parinfer to find the unclosed collection
  3. Verify the file wasn't truncated (compare size/checksum or re-export it)

Example fix

// before (file cut at line 3)
(defn f [x]
  (+ x 1)
// after
(defn f [x]
  (+ x 1))
Defensive patterns

Strategy: try-catch

Validate before calling

// Clojure: scan a file for balanced delimiters before load
(defn file-balanced? [f]
  (let [s (slurp f)]
    (zero? (reduce (fn [n c] (({\( inc \) dec \[ inc \] dec \{ inc \} dec} c identity) n)) 0 s))))

Try / catch

// Clojure
(try
  (load-file "src/foo.clj")
  (catch RuntimeException e
    (if (re-find #"EOF while reading, starting at line (\d+)" (.getMessage e))
      (report-truncated-file e)
      (throw e))))

Prevention

When it happens

Trigger: Reading from a LineNumberingPushbackReader (e.g. load-file/REPL) where input ends before the form started at `firstline` is closed: "(defn f []" followed by EOF.

Common situations: Source files with a missing final closing paren; loading a namespace file truncated by a failed save; slurp'd config/data files cut short.

Related errors


AI-assisted analysis of clojure/clojure@f3b143341d (2026-09-09). Data as JSON: /api/errors/691067b34a3db586. Report an issue: GitHub.

Appendix: source

Thrown at src/jvm/clojure/lang/LispReader.java:1408

public static List readDelimitedList(char delim, PushbackReader r, boolean isRecursive, Object opts, Object pendingForms) {
	final int firstline =
			(r instanceof LineNumberingPushbackReader) ?
			((LineNumberingPushbackReader) r).getLineNumber() : -1;

	ArrayList a = new ArrayList();
	Resolver resolver = (Resolver) RT.READER_RESOLVER.deref();

	for(; ;) {

		Object form = read(r, false, READ_EOF, delim, READ_FINISHED, isRecursive, opts, pendingForms,
                           resolver);

		if (form == READ_EOF) {
			if (firstline < 0)
				throw Util.runtimeException("EOF while reading");
			else
				throw Util.runtimeException("EOF while reading, starting at line " + firstline);
		} else if (form == READ_FINISHED) {
			return a;
		}

		a.add(form);
	}
}

public static class CtorReader extends AFn{
	public Object invoke(Object reader, Object firstChar, Object opts, Object pendingForms){
		PushbackReader r = (PushbackReader) reader;
		pendingForms = ensurePending(pendingForms);
		Object name = read(r, true, null, false, opts, pendingForms);
		if (!(name instanceof Symbol))
			throw new RuntimeException("Reader tag must be a symbol");
		Symbol sym = (Symbol)name;
		Object form = read(r, true, null, true, opts, pendingForms);

View on GitHub (pinned to f3b143341d)