{"record":{"id":"5c05809c66559dae","repo":"clojure/clojure","slug":"can-t-let-qualified-name","errorCode":null,"errorMessage":"Can't let qualified name: ","messagePattern":"Can't let qualified name: ","errorType":"exception","errorClass":"clojure.lang.Util+runtimeException","httpStatus":null,"severity":"error","filePath":"src/jvm/clojure/lang/Compiler.java","lineNumber":6818,"sourceCode":"\t\t\t\treturn analyze(context, RT.list(RT.list(FNONCE, PersistentVector.EMPTY, form)));\n\n\t\t\tIPersistentMap dynamicBindings = RT.map(LOCAL_ENV, LOCAL_ENV.deref(),\n\t\t\t                                        NEXT_LOCAL_NUM, NEXT_LOCAL_NUM.deref());\n\n\t\t\ttry\n\t\t\t\t{\n\t\t\t\tVar.pushThreadBindings(dynamicBindings);\n\n\t\t\t\t//pre-seed env (like Lisp labels)\n\t\t\t\tPersistentVector lbs = PersistentVector.EMPTY;\n\t\t\t\tfor(int i = 0; i < bindings.count(); i += 2)\n\t\t\t\t\t{\n\t\t\t\t\tif(!(bindings.nth(i) instanceof Symbol))\n\t\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\t\t\"Bad binding form, expected symbol, got: \" + bindings.nth(i));\n\t\t\t\t\tSymbol sym = (Symbol) bindings.nth(i);\n\t\t\t\t\tif(sym.getNamespace() != null)\n\t\t\t\t\t\tthrow Util.runtimeException(\"Can't let qualified name: \" + sym);\n\t\t\t\t\tLocalBinding lb = registerLocal(sym, tagOf(sym), null,false);\n\t\t\t\t\tlb.canBeCleared = false;\n\t\t\t\t\tlbs = lbs.cons(lb);\n\t\t\t\t\t}\n\t\t\t\tPersistentVector bindingInits = PersistentVector.EMPTY;\n\t\t\t\tfor(int i = 0; i < bindings.count(); i += 2)\n\t\t\t\t\t{\n\t\t\t\t\tSymbol sym = (Symbol) bindings.nth(i);\n\t\t\t\t\tExpr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name);\n\t\t\t\t\tLocalBinding lb = (LocalBinding) lbs.nth(i / 2);\n\t\t\t\t\tlb.init = init;\n\t\t\t\t\tBindingInit bi = new BindingInit(lb, init);\n\t\t\t\t\tbindingInits = bindingInits.cons(bi);\n\t\t\t\t\t}\n\t\t\t\treturn new LetFnExpr(bindingInits, (new BodyExpr.Parser()).parse(context, body));\n\t\t\t\t}\n\t\t\tfinally\n\t\t\t\t{","sourceCodeStart":6800,"sourceCodeEnd":6836,"githubUrl":"https://github.com/clojure/clojure/blob/f3b143341d6efc6428b523b2eaa099a6cc99156e/src/jvm/clojure/lang/Compiler.java#L6800-L6836","documentation":"letfn* locals must be unqualified symbols. If a binding name carries a namespace (e.g. my.ns/f or foo/bar), the compiler throws a RuntimeException because namespace-qualified names cannot become locals.","triggerScenarios":"Compiling letfn* with a qualified symbol as a binding name, e.g. (letfn* [my.ns/f (fn [x] x)] ...), typically from generated or macro-expanded code that resolves symbols too early.","commonSituations":"Macros that build local names inside syntax-quote causing auto-resolved/qualified symbols (ns`foo), or code that stores fully-qualified names in data used for bindings.","solutions":["Use unqualified symbols in bindings: f instead of my.ns/f.","Inside macros, unqualify generated names with (with-local-vars ...) conventions or use plain (gensym) instead of syntax-quoted symbols.","Check macro expansion with macroexpand-1 and strip namespaces via (symbol (name sym)) where appropriate."],"exampleFix":"// before\n`(letfn* [my.ns/f (fn [x] x)] (f 1))\n// after\n(letfn* [f (fn [x] x)] (f 1))","handlingStrategy":"validation","validationCode":"(doseq [n (take-nth 2 bindings)]\n  (when (and (symbol? n) (namespace n))\n    (throw (ex-info \"binding names must be unqualified\" {:name n}))))","typeGuard":"(defn unqualified-bindings? [bindings]\n  (every? #(and (symbol? %) (nil? (namespace %))) (take-nth 2 bindings)))","tryCatchPattern":"(try (eval form)\n  (catch RuntimeException e\n    (when (.startsWith (.getMessage e) \"Can't let qualified name\")\n      (log/error \"qualified local name in\" form))))","preventionTips":["In macros use gensym/auto-gensym (x#) instead of quoted qualified symbols","Avoid syntax-quoting names meant to be locals","Strip namespaces from data-driven identifiers with (symbol (name s))"],"tags":["clojure","compiler","binding-form","namespaces"],"backgroundTag":"invalid-identifier","analyzedSha":"f3b143341d6efc6428b523b2eaa099a6cc99156e","analyzedAt":"2026-09-09T12:04:58.961Z","contentChangedAt":"2026-09-09T12:04:58.961Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}