clojure/clojure · error · RuntimeException

Unexpected number of constructor arguments to

Error message

Unexpected number of constructor arguments to {}: got {}

What it means

When reading the short positional form #RecordName[...] the reader scans the record class's constructors for one whose parameter count matches the number of supplied arguments. If no constructor accepts that arity, it throws listing the class and the argument count received. This happens after class lookup succeeds, so the record name is valid but the arity is wrong.

Solutions

  1. Match the argument count to the record's field count: #user.Point[1 2] for a two-field record.
  2. Reload/redefine the record consistently and re-serialize the data (pr-str) from a live instance.
  3. If extra data must be carried, use the map form #user.Point{:k v} and keep extra keys in the record's extmap-safe behavior, or move them to metadata.

Example fix

// before
#user.Point[1 2 3] ; Point has 2 fields
// after
#user.Point[1 2]
Defensive patterns

Strategy: validation

Validate before calling

(defn arity-matches? [record-class n]
  (some #(= (count (.getParameterTypes ^java.lang.reflect.Constructor %)) n)
        (.getConstructors record-class)))

Try / catch

(try (read-string lit) (catch RuntimeException e (throw (ex-info "record arity mismatch" {:literal lit} e))))

Prevention

When it happens

Trigger: Reading #user.Point[1 2 3] when the defrecord Point has only 2 fields (constructors of arity 2 plus the arity-0 factory), or #user.Point[] with a record having required fields.

Common situations: Record definition changed (fields added/removed) after data was serialized; hand-edited serialized records; copy-pasting literals from a differently-versioned namespace.

Related errors


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

Appendix: source

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

		} else if (form instanceof IPersistentVector) {
			shortForm = true;
		} else {
			throw Util.runtimeException("Unreadable constructor form starting with \"#" + recordName + "\"");
		}

		Object ret = null;
		Constructor[] allctors = ((Class)recordClass).getConstructors();

		if(shortForm)
			{
	        IPersistentVector recordEntries = (IPersistentVector)form;
			boolean ctorFound = false;
			for (Constructor ctor : allctors)
				if(ctor.getParameterTypes().length == recordEntries.count())
					ctorFound = true;

			if(!ctorFound)
				throw Util.runtimeException("Unexpected number of constructor arguments to " + recordClass.toString() + ": got " + recordEntries.count());

			ret = Reflector.invokeConstructor(recordClass, RT.toArray(recordEntries));
			}
		else
			{

			IPersistentMap vals = (IPersistentMap)form;
			for(ISeq s = RT.keys(vals); s != null; s = s.next())
				{
				if(!(s.first() instanceof Keyword))
					throw Util.runtimeException("Unreadable defrecord form: key must be of type clojure.lang.Keyword, got " + s.first().toString());
				}
			ret = Reflector.invokeStaticMethod(recordClass, "create", new Object[]{vals});
			}

		return ret;
	}
}

View on GitHub (pinned to f3b143341d)