clojure/clojure · error · IllegalArgumentException

Missing argument

Error message

Missing argument

What it means

Clojure's cl-format implementation in RT.doFormat processes the ~a (aesthetic) directive by consuming the next argument from the remaining args list. If the format string contains ~a but the argument list is exhausted (args == null), it throws IllegalArgumentException("Missing argument").

Solutions

  1. Provide one argument per directive in the format string.
  2. Count directives (~a, ~s, etc.) in the format string and verify (count args) matches before calling format.
  3. Simplify or correct the format string (remove stray ~a).
  4. Catch IllegalArgumentException around format calls with user-supplied templates.

Example fix

;; before
(format "~a and ~a" "x") ;; Missing argument
;; after
(format "~a and ~a" "x" "y")
Defensive patterns

Strategy: validation

Validate before calling

(defn arg-count-ok? [fmt args]
  (>= (count args) (count (re-seq #"~[as]" fmt))))

Try / catch

(try (apply format fmt args)
  (catch IllegalArgumentException e
    (throw (ex-info "format template/argument mismatch" {:fmt fmt} (ex-cause e)))))

Prevention

When it happens

Trigger: Calling (format "~a~a" "only-one-arg") — a format string with more directives (~a, and analogously ~s) than supplied arguments.

Common situations: Format strings edited after the argument list changed, dynamic format strings built from user config whose directive count doesn't match the values passed, porting CL format templates.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at src/jvm/clojure/lang/RT.java:2108

	return null;
}

static public ISeq doFormat(Writer w, String s, ISeq args) throws IOException{
	for(int i = 0; i < s.length();) {
		char c = s.charAt(i++);
		switch(Character.toLowerCase(c)) {
			case '~':
				char d = s.charAt(i++);
				switch(Character.toLowerCase(d)) {
					case '%':
						w.write('\n');
						break;
					case 't':
						w.write('\t');
						break;
					case 'a':
						if(args == null)
							throw new IllegalArgumentException("Missing argument");
						RT.formatAesthetic(w, RT.first(args));
						args = RT.next(args);
						break;
					case 's':
						if(args == null)
							throw new IllegalArgumentException("Missing argument");
						RT.formatStandard(w, RT.first(args));
						args = RT.next(args);
						break;
					case '{':
						int j = s.indexOf("~}", i);    //note - does not nest
						if(j == -1)
							throw new IllegalArgumentException("Missing ~}");
						String subs = s.substring(i, j);
						for(ISeq sargs = RT.seq(RT.first(args)); sargs != null;)
							sargs = doFormat(w, subs, sargs);
						args = RT.next(args);
						i = j + 2; //skip ~}

View on GitHub (pinned to f3b143341d)