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:
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.
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)
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?
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: