Why would the following work (with no visible errors) in my REPL but not in my app?
(def v [[1 2][3 4]])
(assoc v 0 (assoc (v 0) 0 5))
output in REPL: [[5 2][3 4]]
If I include both lines of code, I get the browser error/warning:
Uncaught TypeError: can't access property "call", app-name.core.v is undefined
core.cljs:____
where __ is the line number of the second line of code above, the assoc form.
(By the way, doing the same thing but using assoc-in, (assoc-in v [0 0] 5)), does not generate that browser error/warning.)
EDIT:
If I comment out the second line of code, I get a different browser error/warning:
Uncaught Error: Key must be integer
call core.cljs:5901
core.cljs:1067
Though it doesn't report the code line number, it must be associated with the first line of code above since commenting out the first line of code results in no errors at all.You seem to have both v and e in the example that doesn't work... and since the error you provided refers to v, I suspect what you typed in the REPL and what you ran via compilation in the browser are not actually the same code.
When I correct e to v in your first example, it works in the cljs REPL:
cljs.user=> (def v [[1 2][3 4]])
#'cljs.user/v
cljs.user=> (assoc v 0 (assoc (v 0) 0 5))
[[5 2] [3 4]]The v/e discrepancy was just because of an error I made when pasting and altering code here. My actual variable was e, but I was rewriting that to v for clarity of seeing that it is a vector. Fixed now.
Yes, it works in the REPL, as you say, but when I have the exact same lines of code in my core.cljs and then compile and serve to browser, in the browser console I get the errors/warnings mentioned.
If it was the same code, it would behave the same way. I suspect you compiled it in the middle of your rewriting and either have a stray v in your code or you have (def e ..) instead of (def v ..) 🙂
It was definitely the same code, but I will test it a 4th time just to be very, very sure...
(def e [[1 2][3 4]])
(assoc e 0 (assoc (e 0) 0 5))
definitely works in my REPL every time,
but generates the "Uncaught TypeError" in my browser every time.
(def e [[1 2][3 4]])
alone definitely works in my REPL every time,
but generates the "Uncaught Error" in my browser every time.
(I also sometimes do and don't get a many-line broken pipe error message "Exception in thread [...]" in the console (not browser console) when compiling and running the very same code, but that is a red herring since those seem to happen once in a while randomly.)The code looks fine. Have you tried removing all the compilation artifacts and re-compiling that code?
I don't know what that would mean. I looked up the term and I think you mean outputs from previous compiles. That would be a huge number of files and directories to delete? But is that really needed when I can get to a no-error state just by commenting out the offending lines of code?
It should be just a single directory with a whole bunch of stuff in it. It shouldn't be needed, but it's something that should be ruled out first because it's so easy to do.
A potential explanation to the behavior that you see is that maybe you're overriding some value with that def.
By the way, my real use case (which I was building up to) is applying those functions to a vector that is an atom (well, one of those functions, either assoc or assoc-in). The version of the code for an atom vector runs into a similar situation (but with different kinds of errors). This code
(def f (atom [[1 2][3 4]]))
(swap! f assoc 0 (assoc (@f 0) 0 7))
works in the REPL but when part of the compiled app generates the following browser error message
Uncaught Error: No protocol method IDeref.-deref defined for type undefined:
cljs$core$missing_protocol core.cljs:357
cljs$core$IDeref$_deref$dyn_11943 core.cljs:719
cljs$core$_deref core.cljs:719
cljs$core$deref core.cljs:1542
This code (using assoc-in instead of assoc)
(def f (atom [[1 2][3 4]]))
(swap! f assoc-in [1 0] 8)
works in the REPL but when part of the compiled app generates the following browser error message
Uncaught Error: No protocol method ISwap.-swap! defined for type undefined:
cljs$core$missing_protocol core.cljs:357
G__11987__4 core.cljs:902
cljs$core$IFn$_invoke$arity$4 core.cljs:902
cljs$core$IFn$_invoke$arity$4 core.cljs:4709
cljs$core$swap_BANG_ core.cljs:4693
and this code
(def f (atom [[1 2][3 4]]))
alone (just the first line from both blocks of code above) works in the REPL but when part of the compiled app generates the following browser error message:
Uncaught TypeError: cljs.core.atom.call(...).call is not a function
<anonymous> core.cljs:1073
How exactly do you compile the code?
Do you have only a single compilation process running?
> It should be just a single directory with a whole bunch of stuff in it. So the .../app-name/out/ directory? Just delete all of that? OK, I will try that.
For my app I have just taken the CLJS Quick Start Guide as a basis and added to that.
I made an index.html and a style.css and I have all my CLJS in core.cljs (if that answers your question about number of compliation processes?) and I have the same directory structure as with the quick start guide hello world program (.
I compile with this command, which has been working so far:
JAVA_CMD=~/Documents/programming/JDKs/jdk-26.0.2/bin
/java clj -M --main cljs.main --watch src --compile app-name.core --repl
By the "number of processes" I meant whether you have only that one instance of clj running or if there are multiple such instances.
Should be only one. I run it, check the app functionality and any error messages in the browser, and then close the browser tab and hit [Ctrl]+[c] in my console to terminate the clj process.
No clue, sorry. I've never really used the vanilla compiler. Just tried, it gives me OOM from its Clojure code while trying to print... something. In a bare-bones project.
Deleting the entire out/ directory before compiling worked! So that's just a thing a person has to try sometimes?? Very odd. What did you mean about possibly overwriting a def?
If you have a lot of code, you might end up with something like
(def x 1)
...
(def x 2)> So that's just a thing a person has to try sometimes?? Very odd. Stuff like this shouldn't happen, but might if file modification timestamps get mangled somehow. Who knows what's going on on your machine.
Whoa, whoa, whoa. Actually it looks like just now it wasn't compiling the app in the directory I wanted it to! I had made a 2nd copy of my app directory to mess with (delete entire out/ subdirectory, and then compile), and have given that a new name of course (can't have same name as original directory). ...but then I figured the compilation wouldn't work with an altered name because of something like a namespace issue, so I changed the name of my original folder (appending "change this name back after testing temporary impostor directory"), and then I changed the name of the new directory to match the original name of the original directory. After deleting the out/ subdir and doing the compilation test, the webapp worked without errors, but then when I looked in the dir there was still no out/ subdir! I checked the original (and now renamed) folder, and that seems to have received the newly compiled files. So clj was compiling a program in a dir other than the one it was run from?!
Most likely, you still have a clj process somewhere with --watch. The process has a handle on the original out, so renaming doesn't change anything.
(Maybe, speculating here.)
Or it is possible that if I • copied dir1 to dir2 • renamed dir1 to dir3 • renamed dir2 to dir1 • all not in my console (but in a file explorer GUI app) that my console, while still reporting being in the dir1, would actually be operating in dir3?
No clue, I'm not an oracle. :) I have no idea what's going on with your PC.
I already did cd .. so I missed my chance to test that theory and do ls and see if the dir the console is working had an out/ folder.
Mmm. Can you send me a screenshot of how your terminal looks?
> Most likely, you still have a clj process somewhere with --watch. The process has a handle on the original out, so renaming doesn't change anything.
This is interesting, but I don't see how I could have a clj process I don't know about since I always shut down (with Ctrl-c) the current one before running a new one. (I have to just to get out of the REPL and get my normal command line back.)
I am aware that you can spin off processes from actively printing to the console window, but I am not doing that.
I dunno, you can try pgrep.
I just, in the console, left the app dir and then went into the (new) one with the app name (again?). I compiled and ran and got the same error I had been getting. I then deleted the out/ subdir and compiled and ran again and still got the error.
Out of curiosity, what's in the out/app_name/core.js file?
Ah, OK. I was worrying you cannot even tell the current directory without interrupting the current program and running ls.
.cpcache is irrelevant.
> Out of curiosity, what's in the out/app_name/core.js file?
That is a fairly dense JS file with about 470 lines.
Does app-name.core have other code than the one you pasted above? Apart from the (ns ...) form.
In core.js, I found the following JS code corresponding to my CLJS code to do with assoc and assoc-in:
mastermind_2026_07.core.e = new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(1),(2)], null),new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(3),(4)], null)], null).call(null,mastermind_2026_07.core.f = cljs.core.atom.call(null,new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(1),(2)], null),new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(3),(4)], null)], null)),cljs.core.assoc.call(null,mastermind_2026_07.core.e,(0),cljs.core.assoc.call(null,mastermind_2026_07.core.e.call(null,(0)),(0),(5))),cljs.core.assoc_in.call(null,mastermind_2026_07.core.e,new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(1),(0)], null),(6)),cljs.core.swap_BANG_.call(null,mastermind_2026_07.core.f,cljs.core.assoc,(0),cljs.core.assoc.call(null,cljs.core.deref.call(null,mastermind_2026_07.core.f).call(null,(0)),(0),(7))),cljs.core.swap_BANG_.call(null,mastermind_2026_07.core.f,cljs.core.assoc_in,new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(1),(0)], null),(8)),mastermind_2026_07.core.e2 = cljs.core.assoc.call(null,mastermind_2026_07.core.e,(0),cljs.core.assoc.call(null,mastermind_2026_07.core.e.call(null,(0)),(0),(5))),mastermind_2026_07.core.e3 = cljs.core.assoc_in.call(null,mastermind_2026_07.core.e,new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [(1),(0)], null),(6)),cljs.core.println.call(null,(""+cljs.core.str.cljs$core$IFn$_invoke$arity$1(mastermind_2026_07.core.e2))),cljs.core.println.call(null,(""+cljs.core.str.cljs$core$IFn$_invoke$arity$1(mastermind_2026_07.core.e3))),cljs.core.println.call(null,(""+cljs.core.str.cljs$core$IFn$_invoke$arity$1(mastermind_2026_07.core.f))),console.log((""+cljs.core.str.cljs$core$IFn$_invoke$arity$1(mastermind_2026_07.core.e2))),console.log((""+cljs.core.str.cljs$core$IFn$_invoke$arity$1(mastermind_2026_07.core.e3))),console.log((""+cljs.core.str.cljs$core$IFn$_invoke$arity$1(mastermind_2026_07.core.f))));And what's the current CLJS code that lead to that JS code?
And what's the current error?
> Does app-name.core have other code than the one you pasted above? Apart from the (ns ...) form.
You mean my core.cljs?
If so, yes, lots. It has lots more, but all of that works without the problematic lines, and no I am not trying to define the same variables more than once.
A 1kloc! Man, you gotta isolate issues. I thought you had maybe a few dozen lines. The fact that an extra line makes something misbehave doesn't necessarily mean that the issue is with that line. Please bisect and come back with a minimal reproducible example, otherwise we're just stumbling in the dark here. Or have you already done that and it fails in exactly the same way with just the two lines you pasted at the start?
I actually see the issue.
Line 1077.
This is exactly why you gotta create an MRE (Minimal Reproducible Example) when something doesn't work and you cannot figure out why. In 90% of cases, people figure it out during the process of creation of an MRE.
Probably 80% of those LOC are comment lines, of things I tried and things I learned. ...but yes, there is a lot more code. I could make a new project and just try the offending lines, especially since for once they're not connected with the rest of my program and were me just replicating stand-alone testing I was doing in the REPL.
I actually see the issue.> Line 1077. That set of parens is just there so I could easily turn that whole block off with #(_). Are superfluous wrapping parens not allowed? I thought for sure I had used them that way before.
Are superfluous wrapping parens not allowed?Of course not. Parentheses are for calling functions, using macros, and some built-in specials (like
do).
((f)) is a valid expression where (f) is supposed to return something callable, which is then called without arguments.When it was working, you probably used (do ...).
And you comment whole forms out with #_ in front of them - not just #.
And you comment whole forms out withYes. It looks like Slack wouldn't let me enter that (without it being in a code block), and mangled it to remove the first underscore. > When it was working, you probably used#_in front of them - not just#.
(do ...).
I haven't done that before, but I certainly will now if I ever want to turn code blocks off and on. I think what actually happened is that I only ever turned code off like that, and only now for the first time was trying to turn code back on by removing the #_I do find it strange that the CLJS parser couldn't recognize an error being an extra set of parens, and sent me down the road to getting 4 (or more?) spurious errors instead.
A very common approach, if you just want to experiment with something in your REPL and don't want that code to be executed when the namespace is loaded during a normal operation, is to use so-called "rich comments".
Basically you use (comment ...) instead of (do ...), that's it.
It's similar to #_(...), but uncommenting is a single paredit command away, and it's more explicit.
Clojure-aware editors allow you to then run forms within (comment ...) independently.
But I guess it is because of what you wrote about there being instances of ((x)) being valid.
> I do find it strange that the CLJS parser couldn't recognize an error being an extra set of parens
Because it is not an error, it's valid code. It's the same as ((f)).
In any case, the main lesson is that you should be trying to create MREs when stuff doesn't work. :)
An MRE in this case would have been so much simpler to make than usual, too!
It was not related to any variables or functions in my app!
I was also pretty certain the source of the errors was those specific lines, though.
I can't believe an extra set of parens caused all of those disparate errors. Thanks for helping me get to the bottom of it.
from the start of the thread:
Uncaught TypeError: can't access property "call", app-name.core.v is undefined
<anonymous> core.cljs:____
that means "something that is not a function was wrapped in parens"functions implement callable, which defines a "call" method
OK, thanks! I've added that to my notes (which at this time mostly consist of a growing number of comment lines in the core.cljs for the little app I am trying to build, giving post-mortems on bits of code that have not worked out but that I have left in place commented out as warnings to myself)!
I struggle with deciding between passing in functions arguments as a single map or the usual way with arity > 1. This is regarding functions that will never be partially applied (usually simple functions that return hiccup). I have noticed the following: • A single map has the benefit or not requiring the memorization of an arbitrary argument order. Especially beneficial in Clojure where destructuring is idiomatic and IDE autocompletion isn't necessary. • The usual higher arity form is conceptually the same as a 1-arity version where the argument vector is destructured by default. Thus, the question does truly seems to be able to be boiled down to whether a vector or a map is more appropriate for the unary function in question. I fail to see what the downside of using a map is, especially considering that vectors are associative structures too, only in a way that seems to be of no benefit here. The reason I am skeptical is that this is an idea of my own, and I am a beginner, so I cannot trust that I am not missing something here.
It depends™.
Clojure's core libs have plenty of functions of either kind, and even functions that take n parameters and options (e.g. ).
My take is that n-ary functions are nicer when you aren't passing pre-built data in, and don't have the overhead of destructuring and potential allocations, while map functions are easier to change.
Remembering parameters is about as difficult with either case, though IDEs have you covered there.
Personally, if a function has one, two, maybe three parameters, for me, that is okay. More than that, shove it into a map and be done with it 🙂
Tis not a hard or fast rule, there are times I'm stricter, times I'm more lenient, but generally, so long as I can reason about the function and the arity (i.e., keep it in my head) then I do what I think is best. Key also, is to name your parameter something sensible - then, as said before, your IDE can help you see what you're about to invoke 🙂
so, yes, "It Depends™" 🙂
By default I use to a hash map for all function arguments, with a specification (clojure.spec or malli) that describes the hash map arguments. This approach makes testing (generative) and code refactor so much easier, especially over time.