Skip to content

SSL CERTIFICATE_VERIFY_FAILED #651

Description

@Beforerr

Affects: PythonCall

Describe the bug

After upgrading Julia to 1.12-rc, it seems I could not connect to the remote server because of SSL fail (for package https://github.com/SciQLop/Speasy.jl).
However, this bug only appears locally, not in CI, which is very weird. I checked the cert paths from Python, and the result is different from the previous discussion #493 , so maybe they are related.

julia> using PythonCall

julia> @py import ssl

julia> ssl.get_default_verify_paths()
Python: DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/workspace/destdir/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/workspace/destdir/ssl/certs')

Your system

julia> versioninfo()
Julia Version 1.12.0-rc1
Commit 228edd6610b (2025-07-12 20:11 UTC)
Platform Info:
  OS: macOS (arm64-apple-darwin24.0.0)
  CPU: 8 × Apple M1 Pro
  LLVM: libLLVM-18.1.7 (ORCJIT, apple-m1)
  GC: Built with stock GC
Threads: 1 default, 1 interactive, 1 GC (on 6 virtual cores)
julia> Pkg.status()
Project Speasy v0.4.2
Status `~/src/Speasy.jl/Project.toml`
  [2569d6c7] ConcreteStructs v0.2.3
  [992eb4ea] CondaPkg v0.2.29
  [46f1a544] NanoDates v1.0.3
  [6099a3de] PythonCall v0.9.26
  [0b37b92c] SpaceDataModel v0.1.12
  [10745b16] Statistics v1.11.1
  [1986cc42] Unitful v1.24.0
  [ade2ca70] Dates v1.11.0

Activity

  1. Beforerr commented on Aug 12, 2025

    @Beforerr
    Author

    Solved. It turned out to be macOS setting problem. (https://support.apple.com/en-in/guide/keychain-access/kyca11871/mac

  2. Beforerr commented on Aug 30, 2025

    @Beforerr
    Author

    Sorry to reopen. But I think the issue is not solved for Julia 1.12. It fails on Ubuntu CI https://github.com/SciQLop/Speasy.jl/actions/runs/17310489122/job/49143456845

  3. cjdoris commented on Aug 30, 2025

    @cjdoris
    Member

    What's the bug? You haven't shown any errors.

  4. Beforerr commented on Aug 30, 2025

    @Beforerr
    Author

    I think the bug is the Python ssl library fail to load from Python openssl_cafile, instead it points to /workspace/.... And when using ssl from Python, it just could not verify the certificate

    julia> ssl.get_default_verify_paths()
    Python: DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/workspace/destdir/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/workspace/destdir/ssl/certs')
    
  5. ymiftah commented on Sep 4, 2025

    @ymiftah

    I encountered a similar issue, example code:

    @py import urllib
    api_url = "https://services.ga.gov.au/gis/rest/services/National_Electricity_Infrastructure/MapServer/2/query?where=state%20%3D%20'Victoria'&outFields=class,name,operationalstatus,state,spatialconfidence,revised,st_length(shape),capacitykv,ga_guid,length_m&outSR=4326&f=geojson"
    urllib.request.urlopen(api_url)
    
    > ERROR: Python: URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1010)>
    
    julia> versioninfo()
    Julia Version 1.11.6
    Commit 9615af0f269 (2025-07-09 12:58 UTC)
    Build Info:
      Official https://julialang.org/ release
    Platform Info:
      OS: Linux (x86_64-linux-gnu)
      CPU: 16 × AMD Ryzen 9 5900HS with Radeon Graphics
      WORD_SIZE: 64
      LLVM: libLLVM-16.0.6 (ORCJIT, znver3)
    Threads: 8 default, 0 interactive, 4 GC (on 16 virtual cores)
    Environment:
      JULIA_EDITOR = code
      JULIA_VSCODE_REPL = 1
      JULIA_NUM_THREADS = 8
    

    Worth noting, no error thrown with requests

    @py import requests
    r = requests.get(api_url)
    
    > Python: <Response [200]>
    
  6. cgarling commented on Sep 20, 2026

    @cgarling
    Contributor

    I'm encountering an issue on Julia 1.12 presenting a similar openssl_cafile='/workspace/destdir'related error. My diagnosis is below.

    Julia 1.12 is the first release to ship libssl.so.3 / libcrypto.so.3 in lib/julia/. As far as I can tell,julia does not load them, but I think something in the using PythonCall path must (I haven't done a full trace on this). Once loaded, Julia's copy occupies the libssl.so.3 SONAME. When CPython then dlopens _ssl, the loader reuses the already-loaded library instead of following the interpreter's RPATH to its own. /proc/self/maps confirms only Julia's copies are mapped. Julia's OpenSSL bakes OPENSSLDIR in at compile time, so its defaults come out as /workspace/destdir/ssl/..., which of course are garbage. CPython maps any default that is not an existing file or directory to None, so the trust store is empty and verification cannot succeed. Julia's own HTTPS is unaffected because Julia never uses OpenSSL's compiled-in defaults; it passes libcurl a bundle from NetworkOptions explicitly.

    I had an agent check different Julia versions pointing PythonCall.jl at the same Python installation (a pixi env, _ssl dynamically linked), where I have not set SSL_CERT_FILE manually, results are

    Julia libssl mapped ssl.OPENSSL_VERSION openssl_cafile exists urlopen
    1.10.11 the env's own 3.5.7 <env>/ssl/cert.pem yes OK
    1.11.9 the env's own 3.5.7 <env>/ssl/cert.pem yes OK
    1.12.6 Julia's 3.5.4 /workspace/destdir/ssl/cert.pem no FAIL

    Whether this can be reproduced seems to depend on how the Python used links its _ssl. If the Python is linked dynamically against libssl.so.3 (e.g., conda-forge, pixi) it's affected because it picks up Julia's declared library. If the Python is statically linked (like a uv managed environment I had lying around) I couldn't reproduce it.

    Proposed Solution

    The following fixes the problem for me

    import NetworkOptions
    get!(ENV, "SSL_CERT_FILE", NetworkOptions.ca_roots_path())
    using PythonCall

    This names a bundle explicitly rather than relying on the compiled-in defaults, so it fixes any variant where those defaults are the problem, whatever broke them.

    PythonCall could do the same in init_context() (src/C/context.jl), just before Py_InitializeEx, since it knows it is embedding CPython into a process that may already hold Julia's OpenSSL. NetworkOptions is a stdlib, so no new dependency. The get! leaves existing user setting alone, so hopefully it will be safe, but I haven't fully thought through what else this might affect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions