CondaPkg installs incompatible free-threaded NumPy

I’ve been working on a small Python project recently, and I’m now considering using PythonCall again to speed up a few places more easily. But when I went to make a fresh Julia environment with current versions, I hit a snag after installing NumPy:

julia> np = pyimport("numpy")
ERROR: Python: ImportError:

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!

Importing the numpy C-extensions failed. This error can happen for
many reasons, often due to issues with your setup or how NumPy was
installed.
The following compiled module files exist, but seem incompatible
with with either python 'cpython-314' or the platform 'win32':

  * _multiarray_umath.cp314t-win_amd64.lib
  * _multiarray_umath.cp314t-win_amd64.pyd

At first I didn’t even notice what was off; the omitted remainder of the printout and files indicated the correct CPython (3.14.3) and NumPy (2.4.3) versions that match the working venv environment’s. When I looked up the file name there though, the discrepancy stands out:

_multiarray_umath.cp314-win_amd64.lib

I’m not entirely certain if this is true, but I’m reading that extra t means CondaPkg installed NumPy built for free-threaded CPython, which I definitely am not using in Julia:

julia> @pyexec "import sys; print(sys._is_gil_enabled())" # False = free-threaded
True

conda rm and repeated conda add gets the same files again. Why is this happening and how do I get the right NumPy build? I’m wondering if I have some bad environment variable somewhere, but the last time I remember using PythonCall was before the release of experimental free-threaded CPython.

How did you set up your python environment? CondaPkg? Can you share CondaPkg.toml?

I didn’t do any of the manual options for setting up Python this time, but I can’t rule out doing that a couple years ago and leaving some lingering effect. Just add PythonCall, add CondaPkg, then conda add numpy in a fresh environment, leaving this CondaPkg.toml:

[deps]
numpy = ""

If it helps,

  • CondaPkg is using pixi
  • I have a global installation of GIL-enabled Python 3.14.3, installed with the relatively new juliaup-resembling Python install manager for the first time.
  • Julia versioninfo():
Julia Version 1.12.5
Commit 5fe89b8ddc (2026-02-09 16:05 UTC)
Build Info:
  Official https://julialang.org release
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 8 × Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
  WORD_SIZE: 64
  LLVM: libLLVM-18.1.7 (ORCJIT, icelake-client)
  GC: Built with stock GC
Threads: 1 default, 1 interactive, 1 GC (on 8 virtual cores)

What is the output of pkg> conda run python --version?

Python 3.14.3, consistent with all the other ways indicating the Python version.

Hmm. Can you post the full output of pkg> conda resolve --force (in the broken env)?

julia> using CondaPkg

(@v1.12) pkg> conda run python --version
Python 3.14.3

(@v1.12) pkg> conda resolve --force
    CondaPkg Found dependencies: C:\Users\Benny\.julia\environments\v1.12\CondaPkg.toml
    CondaPkg Found dependencies: C:\Users\Benny\.julia\packages\PythonCall\83z4q\CondaPkg.toml
    CondaPkg Found dependencies: C:\Users\Benny\.julia\packages\CondaPkg\8GjrP\CondaPkg.toml
    CondaPkg Initialising pixi
             │ C:\Users\Benny\.julia\artifacts\aa881b8313f97d7b8797934574a1cfe551f85222\bin\pixi.exe
             │ init
             │ --format pixi
             └ C:\Users\Benny\.julia\environments\v1.12\.CondaPkg
✔ Created C:\Users\Benny\.julia\environments\v1.12\.CondaPkg\pixi.toml
    CondaPkg Wrote C:\Users\Benny\.julia\environments\v1.12\.CondaPkg\pixi.toml
             │ [dependencies]
             │ openssl = ">=3, <3.6"
             │ numpy = "*"
             │
             │     [dependencies.python]
             │     channel = "conda-forge"
             │     build = "*cp*"
             │     version = ">=3.10,!=3.14.0,!=3.14.1,<4"
             │
             │ [project]
             │ name = ".CondaPkg"
             │ platforms = ["win-64"]
             │ channels = ["conda-forge"]
             │ channel-priority = "strict"
             └ description = "automatically generated by CondaPkg.jl"
    CondaPkg Updating packages
             │ C:\Users\Benny\.julia\artifacts\aa881b8313f97d7b8797934574a1cfe551f85222\bin\pixi.exe
             │ update
             └ --manifest-path C:\Users\Benny\.julia\environments\v1.12\.CondaPkg\pixi.toml
Environment: default
  + C bzip2            1.0.8 h0ad9c76_9
  + C ca-certificates  2026.2.25 h4c7d964_0
  + C libblas          3.11.0 6_hf2e6a31_mkl
  + C libcblas         3.11.0 6_h2a3cdd5_mkl
  + C libexpat         2.7.4 hac47afa_0
  + C libffi           3.5.2 h3d046cb_0
  + C libhwloc         2.12.2 default_h4379cf1_1000
  + C libiconv         1.18 hc1393d2_2
  + C liblapack        3.11.0 6_hf9ab0e9_mkl
  + C liblzma          5.8.2 hfd05255_0
  + C libmpdec         4.0.0 hfd05255_1
  + C libsqlite        3.52.0 hf5d6505_0
  + C libwinpthread    12.0.0.r4.gg4f2fc60ca h57928b3_10
  + C libxml2          2.15.2 h5d26750_0
  + C libxml2-16       2.15.2 h692994f_0
  + C libzlib          1.3.2 hfd05255_2
  + C llvm-openmp      22.1.1 h4fa8253_0
  + C mkl              2025.3.1 hac47afa_11
  + C numpy            2.4.3 py314hffb9209_0
  + C openssl          3.5.5 hf411b9b_1
  + C python           3.14.3 h7c1dbca_1_cp314t
  + C python_abi       3.14 8_cp314t
  + C tbb              2022.3.0 h3155e25_2
  + C tk               8.6.13 h6ed50ae_3
  + C tzdata           2025c hc9c84f9_1
  + C ucrt             10.0.26100.0 h57928b3_0
  + C vc               14.3 h41ae7f8_34
  + C vc14_runtime     14.44.35208 h818238b_34
  + C vcomp14          14.44.35208 h818238b_34
  + C zstd             1.5.7 h534d264_6
    CondaPkg Installing packages
             │ C:\Users\Benny\.julia\artifacts\aa881b8313f97d7b8797934574a1cfe551f85222\bin\pixi.exe
             │ install
             └ --manifest-path C:\Users\Benny\.julia\environments\v1.12\.CondaPkg\pixi.toml
✔ The default environment has been installed.

I tried to check if that somehow fixed the NumPy issue but now PythonCall is broken. Not sure if it broke here or at conda run python --version, but it was definitely working in the prior session where I made the post.

julia> using PythonCall
ERROR: InitError: UndefRefError: access to undefined reference
Stacktrace:
  [1] _pyjl_new(t::Ptr{PythonCall.C.PyObject}, ::Ptr{PythonCall.C.PyObject}, ::Ptr{PythonCall.C.PyObject})
    @ PythonCall.JlWrap.Cjl C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\JlWrap\C.jl:24
  [2] PyObject_CallObject
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\C\pointers.jl:300 [inlined]
  [3] PyJuliaValue_New
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\JlWrap\C.jl:392 [inlined]
  [4] macro expansion
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\Core\Py.jl:118 [inlined]
  [5] pyjl(t::PythonCall.Py, v::Module)
    @ PythonCall.JlWrap C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\JlWrap\base.jl:7
  [6] pyjl
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\JlWrap\any.jl:400 [inlined]
  [7] Py
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\JlWrap\base.jl:141 [inlined]
  [8] macro expansion
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\Core\Py.jl:117 [inlined]
  [9] pysetattr
    @ C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\Core\builtins.jl:78 [inlined]
 [10] setproperty!(x::PythonCall.Py, k::Symbol, v::Module)
    @ PythonCall.Core C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\Core\Py.jl:281
 [11] __init__()
    @ PythonCall.JlWrap C:\Users\Benny\.julia\packages\PythonCall\83z4q\src\JlWrap\JlWrap.jl:70
 [12] run_module_init(mod::Module, i::Int64)
    @ Base .\loading.jl:1443
 [13] register_restored_modules(sv::Core.SimpleVector, pkg::Base.PkgId, path::String)
    @ Base .\loading.jl:1431
 [14] _include_from_serialized(pkg::Base.PkgId, path::String, ocachepath::String, depmods::Vector{Any}; register::Bool)
    @ Base .\loading.jl:1319
 [15] _include_from_serialized
    @ .\loading.jl:1274 [inlined]
 [16] _require_search_from_serialized(pkg::Base.PkgId, sourcepath::String, build_id::UInt128, stalecheck::Bool; reasons::Dict{…}, DEPOT_PATH::Vector{…})
    @ Base .\loading.jl:2115
 [17] _require_search_from_serialized
    @ .\loading.jl:2009 [inlined]
 [18] __require_prelocked(pkg::Base.PkgId, env::String)
    @ Base .\loading.jl:2627
 [19] _require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:2493
 [20] macro expansion
    @ .\loading.jl:2421 [inlined]
 [21] macro expansion
    @ .\lock.jl:376 [inlined]
 [22] __require(into::Module, mod::Symbol)
    @ Base .\loading.jl:2386
 [23] require(into::Module, mod::Symbol)
    @ Base .\loading.jl:2362
 [24] top-level scope
    @ REPL[1]:1
during initialization of module JlWrap
Some type information was truncated. Use `show(err)` to see complete types.

So I redid precompilation to fix THAT, and somehow I ended up with free-threaded CPython:


(@v1.12) pkg> precompile

julia> using PythonCall

julia> @pyexec "import sys; print(sys._is_gil_enabled())"
False

julia> @pyexec "import sys; print(sys.version)"
3.14.3 free-threading build | packaged by conda-forge | (main, Feb  9 2026, 21:56:46) [MSC v.1944 64 bit (AMD64)]

with which the existing NumPy installation is compatible:

julia> np = pyimport("numpy")
Python: <module 'numpy' from 'C:\\Users\\Benny\\.julia\\environments\\v1.12\\.CondaPkg\\.pixi\\envs\\default\\Lib\\site-packages\\numpy\\__init__.py'>

I don’t want free-threading, and PythonCall is still broken on first import (even if I tried to manually precompile beforehand) in new sessions, but progress?

Indeed this is free-threaded python, and a free-threaded build of numpy.

Seems like your broken env had a mix somehow?

If you want to force the standard build I think you can do conda add python-gil.

Oh PythonCall recently gained experimental compatibility with free-threaded python but I just realised that’s not released yet.

Forgot to share the environment earlier, but not even released on either of these packages’ versions?

(@v1.12) pkg> st
Status `C:\Users\Benny\.julia\environments\v1.12\Project.toml`
  [992eb4ea] CondaPkg v0.2.34
  [6099a3de] PythonCall v0.9.31

So how am I even getting the free-threading builds, let alone in such a chaotic way?

Because there has never been anything stopping conda from installing the free-threaded build - PythonCall asks for python and you get the build that you get.

The recent compatibility I mentioned is that PythonCall actually works with the free-threaded build now. Before it would crash. Until that is released you can try pkg> add PythonCall#main.

If it’s conda giving the wrong NumPy and CPython builds, wouldn’t that be a much more widespread issue affecting all users of previous PythonCall and CondaPkg releases ever since free-threading arrived late 2024? And I still suspect something went wrong on my end because free-threading is still not the default option; GIL-enabled CPython showed up in the prior system install and the initial PythonCall install before I tried adding NumPy. Are there any free-threading-related environment variables or settings for PythonCall I should check?

AFAIU there’s nothing (in the way dependencies are set up in conda-forge) preventing conda from installing free-threaded python in an environment that only specifies python rather than python-gil. In practice, almost always you do get gil python but I think occasionally conda picks free threaded python - it’ll all depends on the specifics of it’s dependency resolution at that moment in time.

In hindsight, PythonCall should have had a dependency on python_abi to restrict to standard python.

But anyway, like I said, a forthcoming version of PythonCall will work with free threaded python so that won’t be necessary. Or you can conda add python-gil to avoid the free threaded build.

Yeah I’ll nuke the installs and scratchspaces, give that a shot. GIL-enabled Python seems stable across sessions so far. For posterity, my exact steps for that environment:

  1. Fresh environment
  2. ]add CondaPkg
  3. using CondaPkg
  4. ]conda add python-gil
  5. ]add PythonCall
  6. ]conda add numpy
  7. using PythonCall
  8. np = pyimport("numpy")

My deepest thanks for getting me through this!

1 Like