clojure/clojure · error · RuntimeException

Can't create defs outside of current ns

Error message

Can't create defs outside of current ns

What it means

def always creates the var in the current namespace. If a def names a qualified symbol that resolves to an existing var belonging to a different namespace, interning would mutate someone else's namespace, so the compiler refuses with this error (the old "name conflict" message is commented out in the source).

Solutions

  1. Drop the qualifier and def an unqualified symbol in the current namespace, or use a new name to avoid confusion.
  2. If you truly need to set a var in another namespace, use (intern 'other.ns 'var-name value) or eval inside (in-ns 'other.ns).
  3. If you wanted to change the value of the existing var, use alter-var-root (e.g. (alter-var-root #'other.ns/v (constantly new-v))) instead of def.

Example fix

// before
(def clojure.test/*report-counters* {}) ; foreign ns
// after
(alter-var-root #'clojure.test/*report-counters* (constantly {}))
Defensive patterns

Strategy: fallback

Validate before calling

(let [v (resolve sym)]
  (when (and v (not= (ns-name (:ns (meta v))) (ns-name *ns*)))
    (println "var belongs to another ns; use intern or alter-var-root")))

Try / catch

try {
  (eval form)
} catch (RuntimeException e) {
  (if (.contains (.getMessage e) "outside of current ns")
    (intern (symbol (namespace target-sym)) (symbol (name target-sym)) value)
    (throw e))
}

Prevention

When it happens

Trigger: Evaluating (def some.other.ns/existing-var v) where the var exists but its namespace is not the current *ns* and the symbol carries an explicit ns qualifier (the sym.ns == null intern path is skipped).

Common situations: Attempting to override a library var via its fully qualified name; generated code that emits qualified def names; after renaming/moving code so an old qualified def now points at a foreign ns.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at src/jvm/clojure/lang/Compiler.java:554

			else if(RT.count(form) < 2)
				throw Util.runtimeException("Too few arguments to def");
			else if(!(RT.second(form) instanceof Symbol))
					throw Util.runtimeException("First argument to def must be a Symbol");
			Symbol sym = (Symbol) RT.second(form);
			Var v = lookupVar(sym, true);
			if(v == null)
				throw Util.runtimeException("Can't refer to qualified var that doesn't exist");
			if(!v.ns.equals(currentNS()))
				{
				if(sym.ns == null)
					{
					v = currentNS().intern(sym);
					registerVar(v);
					}
//					throw Util.runtimeException("Name conflict, can't def " + sym + " because namespace: " + currentNS().name +
//					                    " refers to:" + v);
				else
					throw Util.runtimeException("Can't create defs outside of current ns");
				}
			IPersistentMap mm = sym.meta();
			boolean isDynamic = RT.booleanCast(RT.get(mm,dynamicKey));
			if(isDynamic)
			   v.setDynamic();
            if(!isDynamic && sym.name.startsWith("*") && sym.name.endsWith("*") && sym.name.length() > 2)
                {
                RT.errPrintWriter().format("Warning: %1$s not declared dynamic and thus is not dynamically rebindable, "
                                          +"but its name suggests otherwise. Please either indicate ^:dynamic %1$s or change the name. (%2$s:%3$d)\n",
                                           sym, SOURCE_PATH.get(), LINE.get());
                }
			if(RT.booleanCast(RT.get(mm, arglistsKey)))
				{
				IPersistentMap vm = v.meta();
				//vm = (IPersistentMap) RT.assoc(vm,staticKey,RT.T);
				//drop quote
				vm = (IPersistentMap) RT.assoc(vm,arglistsKey,RT.second(mm.valAt(arglistsKey)));
				v.setMeta(vm);

View on GitHub (pinned to f3b143341d)