I keep running into this certificate error when trying to make an external request using something like httpkit ๐งต
{:cause "unable to find valid certification path to requested target",
:via
[{:type javax.net.ssl.SSLHandshakeException,
:message
"(certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target",
:at [sun.security.ssl.Alert createSSLException "Alert.java" 130]}
{:type sun.security.validator.ValidatorException,
:message
"PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target",
:at
[sun.security.validator.PKIXValidator
doBuild
"PKIXValidator.java"
387]}
{:type sun.security.provider.certpath.SunCertPathBuilderException,
:message
"unable to find valid certification path to requested target",
:at
[sun.security.provider.certpath.SunCertPathBuilder
build
"SunCertPathBuilder.java"
148]}],
:trace
[[sun.security.provider.certpath.SunCertPathBuilder
build
"SunCertPathBuilder.java"
148]
[sun.security.provider.certpath.SunCertPathBuilder
engineBuild
"SunCertPathBuilder.java"
129]
[java.security.cert.CertPathBuilder build "CertPathBuilder.java" 299]
[sun.security.validator.PKIXValidator
doBuild
"PKIXValidator.java"
382]
[sun.security.validator.PKIXValidator
engineValidate
"PKIXValidator.java"
270]
[sun.security.validator.Validator validate "Validator.java" 256]
[sun.security.ssl.X509TrustManagerImpl
checkTrusted
"X509TrustManagerImpl.java"
284]
[sun.security.ssl.X509TrustManagerImpl
checkServerTrusted
"X509TrustManagerImpl.java"
144]
[sun.security.ssl.CertificateMessage$T13CertificateConsumer
checkServerCerts
"CertificateMessage.java"
1273]
[sun.security.ssl.CertificateMessage$T13CertificateConsumer
onConsumeCertificate
"CertificateMessage.java"
1172]
[sun.security.ssl.CertificateMessage$T13CertificateConsumer
consume
"CertificateMessage.java"
1115]
[sun.security.ssl.SSLHandshake consume "SSLHandshake.java" 421]
[sun.security.ssl.HandshakeContext
dispatch
"HandshakeContext.java"
477]
[sun.security.ssl.SSLEngineImpl$DelegatedTask
run
"SSLEngineImpl.java"
1207]
[org.httpkit.client.HttpsRequest doHandshake "HttpsRequest.java" 91]
[org.httpkit.client.HttpClient doRead "HttpClient.java" 218]
[org.httpkit.client.HttpClient run "HttpClient.java" 519]
[java.lang.Thread run "Thread.java" 1474]]}a usefull sniff test is to curl the url and see if curl trusts the cert
Yeah, curl does. It's "https://google.com"
if it does you may need to update the certs that java trusts, potentially by upgrading java
I was behind a firewall but have removed it. I think some firewall thing is hanging around. I tried to reinstall java and clojure.
what version of java? reinstalled from where?
% which java
/Users/mbp25/.local/share/mise/installs/java/temurin-25.0.0+36.0.LTS/bin/javaI'm using mise for managing my dependencies like Clojure and Java.
how sure are you that java is actually what is being used when you get the stacktrace?
(seems unlikely you would have something old enough to have trouble trusting google's certs though)
You mean how sure am I that it's that version?
that when you ran the code that gave you the error it was actually using that java
like if you have JAVA_HOME set to something else, or started jvm from emacs which might have a different env
if I'm not in a directory being managed by mise:
~ % java --version
The operation couldnโt be completed. Unable to locate a Java Runtime.
Please visit for information on installing Java. ah, I bet the temurin install has its own trust store, where curl is using the macos keychain, and something (is this a work provisioned laptop?) has inserted a root cert in the macos keychain, and something is mitm attacking your traffic
Yeah, it's a work laptop but we made an effort to remove anything that might be MITM'ing my traffic. I'm this close:ok_hand: to a factory reset.
it might be possible to find the java trust store in the temurin-25.0.0+36.0.LTS diractory, and maybe use keytool to dump the certs in it, then compare those to the certs in the keyring
may not be something on your laptop
What do you mean, not something on my laptop?
If you are on a company network they might have some mitm appliance, and require the certs for it to be installed on all provisioned machines
^ Very much this. I have a similar situation on my company machine. One way to potentially confirm would be to look at the cert info for http://google.com in the company machine browser and a "public"/personal machine browser. The http://google.com cert on the "public" machine will likely be issued by something like "Google Trust Services", while on the company machine, it might be issued by something like "my-company-ca" or "SomeSecurityProvider Intermediate CA". If you connect to company stuff via a VPN or something along those lines, the MITM is likely happening on the network, and company machines will have those CAs in their system cert stores (so things like curl will trust them), but a "fresh" java installation usually won't.
I suppose there's no easy path to fix it for all your development needs at once? I've run into similar issues with node, Python, docker, etc.. In the Clojure case I initially patched it by setting some CLJ_JVM_OPTS to use the osx keystore and it fixed deps downloading but for some reason it didn't fix REPL invocations that made requests.
The short-ish, not that helpful answer is "install the certs where they're needed". There might be a company repo of the certs, but different tools are going to have different paths to adding certs/telling a platform to use the system cert store. I'm not aware of a panacean answer.
how can I get an evaluated result here?:
(defmacro example [data]
`(let [foo# ~(first data)]
(cons 'and (list 1 foo#))))
(example [2])
It returns (clojure.core/and 1 2) , but I want 2 .user> (defn example
[data]
(let [foo (first data)]
(and 1 foo)))
#'user/example
user> (example [2])
2Is the purpose here merely practice with macros in particular?
If not, and you're instead looking for general evaluation, then @hhausmanโs answer, using a function, is definitely preferred.
But if you're trying to play with macros themselves, this technically gives you the answer you want
(it explicitly evals the form you created with cons)
(defmacro example [data]
`(let [foo# ~(first data)]
(eval (cons 'and (list 1 foo#)))))
It's effectively the same as
(defmacro example [data]
`(let [foo# ~(first data)]
(cons 'and (list 1 foo#))))
(eval (example [2]))This, a bit simpler, but still a macro, also gives you what you want, i believe, by not consing up a new form in the first place
(defmacro example [data]
`(let [foo# ~(first data)]
(and 1 foo#))) ; edit: corrected by phronmophobicYour call to cons is returning a new form (read: new clojure code); it doesn't evaluate it
๐ฎ
user> (and 1 2)
2
user> ('and 1 2)
2
simple_smileAnd.... well outside the scope of the #beginners channel:
user> (#'and 1 2)
true
๐คญThe above example gives the wrong impression. Try:
(defmacro example [data]
`(let [foo# ~(first data)]
('foo 1 foo#)))
> (example [2])
2
What is happening is that you're invoking a symbol. Invoking a symbol is similar to invoking a keyword. It's more or less equivalent to:
(get 1 'foo 2)
Since 1 doesn't contain 'foo, it returns 2.whoopsie
it would also help if you would specify exactly what you're trying to play with/figure out @okilimnik, there's many many ways to get an output of 2 from both macros and functions :^)
Yes, I'm playing with macros to get more understanding.
In my example the (list 1 foo#) is a simulation of calling another function that accepts foo# as a parameter and returns a form.
So seems there is no way other than using eval ?
Thank you, guys
I doubt you need eval here. You should be able to do:
(defmacro example [data]
`(let [foo# ~(first data)]
(and 1 foo#)))As I said above I need to (list 1 foo#) and then to add and to the resulting form
Can you provide a bit more context about the actual goal? I still donโt think eval is necessary, but itโs hard to give a better answer without more context.
Another way to write it that's a bit more dynamic is:
(defn example3* [data]
(let [foo## (gensym "foo")]
`(let [~foo## ~(first data)]
~(cons 'and (list 1 foo##)))))
(defmacro example3 [data]
(example3* data))
I'm also using a common trick where the macro defers to a pure function that is easier to test.
note: Sometimes you need to refer to a symbol inside of backtick, but also programmatically. I use ## as a suffix for these situations, but that is a thing I came up with and I'm not aware of anyone else that does it.Just based on experience, I have a feeling that the code could be less complicated using some regular old function like some.
Wow @smith.adriane! Thank you so much! That's what I was looking for. And your last point is brilliant as well. It works as I want if I replace cons 'and with every? identity :
(defmacro example [data]
`(let [foo# ~(first data)]
(every? identity (list 1 foo#))))
Iโm pretty sure Iโve seen similar questions here over the years regarding and . ๐
You may want to ponder whether you need a macro at all in this situation.
Does anyone really use the io! macro?
no
Lol that was to the point ๐
What prompted it to be in core then? An experiment that didn't really bear fruit?
It is part of the stm(could apply to swap! to avoid retry io, but doesn't), which itself is rarely used
It's pretty rare, https://cloogle.phronemophobic.com/name-search.html?q=clojure.core%2Fio%21&tables=var-usages
although, @hiredman has tried it before, https://github.com/hiredman/clojurebot/blob/1e8bde92f2dd45bb7928d4db17de8ec48557ead1/src/hiredman/clojurebot/core.clj#L116
Would be interesting to find the age range of those usages
That is a neat idea. There's a couple different ways to measure age, but I think most reasonable methods would be interesting in their own way.
just spot checking and most of the repos haven't been updated in over a decade.