clojure/clojure · error · RuntimeException
fns taking primitives cannot be variadic
Error message
fns taking primitives cannot be variadic
What it means
Clojure only supports primitive arities for non-variadic functions, and only for long/double parameters. If a fn has a primitive-typed signature (method.prim set) and also a rest parameter, the compiler rejects the combination because primitive arities cannot be variadic.
Solutions
- Remove the rest parameter so the fn has fixed arity with primitive params
- Remove the primitive hints so the fn is variadic but boxed
- Split into two functions: a fixed-arity primitive version and a variadic boxed version
- Keep primitive hints only on long/double and only in fixed-arity fns
Example fix
;; before (defn f [^long x & more] (+ x (first more))) ;; after (defn f [^long x] (inc x)) (defn f-variadic [x & more] (apply + x more))
Defensive patterns
Strategy: validation
Validate before calling
(defn primitive-variadic? [params]
(and (some #{'&} params)
(some #(contains? (meta %) :tag) params)))
;; if true, either drop the hint or drop the rest param Prevention
- Use primitive hints (^long, ^double) only in fixed-arity fns
- Provide separate fixed-arity primitive and variadic boxed versions
- Remember only long and double primitives are supported
When it happens
Trigger: Defining (defn f [^long x & rest] ...) or (fn ^long [^double d & more] ...) where a primitive-tagged positional param coexists with a rest param (Compiler.java:6002).
Common situations: Trying to write a high-performance variadic primitive function; adding a & rest param to an existing primitive-arity fn for backward compatibility.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- & arg cannot have type hint
- Can't have fixed arity function with more params than…
- Can't have more than 1 variadic overload
- Can't use & as a local binding
- Cannot coerce to , use a cast instead
AI-assisted analysis of clojure/clojure@f3b143341d (2026-09-09).
Data as JSON: /api/errors/ebdb12e6f69cc48b.
Report an issue: GitHub.
Appendix: source
Thrown at src/jvm/clojure/lang/Compiler.java:6002
throw Util.runtimeException("Invalid parameter list");
}
else
{
Class pc = primClass(tagClass(tagOf(p)));
// if(pc.isPrimitive() && !canBeDirect)
// {
// pc = Object.class;
// p = (Symbol) ((IObj) p).withMeta((IPersistentMap) RT.assoc(RT.meta(p), RT.TAG_KEY, null));
// }
// throw Util.runtimeException("Non-static fn can't have primitive parameter: " + p);
if(pc.isPrimitive() && !(pc == double.class || pc == long.class))
throw new IllegalArgumentException("Only long and double primitives are supported: " + p);
if(state == PSTATE.REST && tagOf(p) != null)
throw Util.runtimeException("& arg cannot have type hint");
if(state == PSTATE.REST && method.prim != null)
throw Util.runtimeException("fns taking primitives cannot be variadic");
if(state == PSTATE.REST)
pc = ISeq.class;
argtypes.add(Type.getType(pc));
argclasses.add(pc);
LocalBinding lb = pc.isPrimitive() ?
registerLocal(p, null, new MethodParamExpr(pc), true)
: registerLocal(p, state == PSTATE.REST ? ISEQ : tagOf(p), null, true);
argLocals = argLocals.cons(lb);
switch(state)
{
case REQ:
method.reqParms = method.reqParms.cons(lb);
break;
case REST:
method.restParm = lb;
state = PSTATE.DONE;
break;View on GitHub (pinned to f3b143341d)