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
- Go to the reported starting line and balance the delimiters from there
- Use a paren-matching editor/parinfer to find the unclosed collection
- 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
- Parse the reported line number from the message to jump straight to the unclosed form
- Use parinfer or a paren-matching editor for source files
- Confirm file saves completed (size changed) before loading
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
- EOF while reading character
- EOF while reading string
- arg literal must be %, %& or %integer
- arg literal not in #()
- Can't resolve
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)