Repository navigation
Open
Description
Describe the issue:
The linalg.inv function is showing consistent crashes with the numpy 2.3.1 and 2.3.2 wheels for win_arm64 (Windows on Arm, WoA) installed from PyPI with Windows fatal exception: access violation.
The traceback in SciPy CI points at this line:
Line 669 in c6b5258
| ainv = _umath_linalg.inv(a, signature=signature) |
Reproduce the code example:
Here is a reproducer:
@pytest.mark.parametrize('dtype', [np.complex64, np.complex128])
@pytest.mark.parametrize('mtype', ['symm', 'herm']) # matrix type
def test_numpy_inv_crash_win_arm64(dtype, mtype):
rng = np.random.default_rng(1723059677121834)
n = 20
A = rng.random((n, n)) + rng.random((n, n))*1j
if np.issubdtype(dtype, np.floating):
A = A.real
A = A.astype(dtype)
A = A + A.T if mtype == 'symm' else A + A.conj().T
ref = np.linalg.inv(A)
It's crashing for all combinations of `complex64`/`complex128` and symmetric/hermitian matrices. `float32`/`float64` dtypes are working fine.Error message:
This ran in SciPy CI with `pytest-xdist` with 2 workers.
Windows fatal exception: access violation
...
Current thread 0x00001f34 (most recent call first):
File "C:\hostedtoolcache\windows\Python\3.12.10\arm64\Lib\site-packages\numpy\linalg\_linalg.py", line 669 in inv
File "C:\a\scipy\scipy\build-install\Lib\site-packages\scipy\linalg\tests\test_lapack.py", line 3527 in test_numpy_inv_crash_win_arm64
File "C:\hostedtoolcache\windows\Python\3.12.10\arm64\Lib\site-packages\_pytest\python.py", line 157 in pytest_pyfunc_call
File "C:\hostedtoolcache\windows\Python\3.12.10\arm64\Lib\site-packages\pluggy\_callers.py", line 121 in _multicall
...Python and NumPy Versions:
Python 3.11/3.12
NumPy 2.3.1/2.3.2
Runtime Environment:
(can't easily provide this, I don't have local hardware)
Context for the issue:
The SciPy tests can be skipped for now, so it's not blocking.
Reacted by MUGUNDAN
Activity
matthew-brett commentedon Jul 26, 2025
@rgommers - do these look like OpenBLAS errors do you think? Would it be worth testing with lapack-liite? @MugundanMCW @khmyznikov - do you have any interest in testing here?
rgommers commentedon Jul 26, 2025
Could be, but could equally well be inside
numpy. Ideally this is reproduced locally and then a stack trace generated. Or even in CI, since it reproducibly crashes there and it seems like the "Windows way" of getting a stack trace is to modify the code - once that's done, may as well push it to CI.Switching to
lapack_liteby passing-Csetup-args=blas=noneto a build is a reasonable proxy, but doesn't get you any more info than whether it's more or less likely to be in OpenBLAS or in NumPy.theAeon commentedon Jul 28, 2025
Currently giving it a go with Arm's blas to see what happens.
theAeon commentedon Jul 28, 2025
Well, I guess that answers the question as to whether this is numpy or openblas:
theAeon commentedon Jul 28, 2025
.....it also passes with the pypi wheel. so either the reproducer is bad or something else is up.
rgommers commentedon Jul 28, 2025
Thanks for digging in @theAeon! It may well be either hardware or compiler specific. It reproducibly crashes on the GitHub
windows-11-armrunners. In scipy/scipy#23133, @MugundanMCW had mixed success trying to reproduce locally, e.g see this comment and this comment.It could be specific to an architecture-specific kernel in OpenBLAS. With
export OPENBLAS_CORETYPE=<arm-family-name>you can force one, with the names given in OpenBLAS's TargetList.txt. I'm not quite sure if all of them are relevant though.@Mousius as our resident Arm expert, do you have any other suggestions here?
theAeon commentedon Jul 28, 2025
Suppose theres also the uarch question-this is an oryon chip (x elite), not sure what the runner chips are (or the other local machines)
matthew-brett commentedon Jul 28, 2025
@theAeon - sorry - this is off-topic - but are the ARM performance libraries an option for PyPI wheels? Are they faster than OpenBLAS? Do they have a compatible license? (Probably current ARM PF license). Can we ship the libraries with the wheel, do you know?
rgommers commentedon Jul 28, 2025
Copying my comment from scipy/scipy#23133 (comment): It's not open source, so I doubt that this will be acceptable. The EULA seems to permit redistribution, but no source code available is a deal breaker I think.
We can always discuss of course, and it'd be nice to see what the binary size is with ArmPL (hopefully close to OpenBLAS and nothing like MKL), but previously we have not wanted to consider this. Maybe once we have variant wheels, it's more of an option to ship alternative BLAS libraries.
theAeon commentedon Jul 28, 2025
So it seems (i can't be sure) that the github runners are older azure arm machines w/ ampere altra chips, which are modified NeoVerse N1. Which are fairly different in terms of simd instruction set support.
Does the CI have logs of which SIMD features are enabled? I think that may be the key here.
rgommers commentedon Jul 28, 2025
For
numpyitself yes, but I already checked and those were the same (it's underSIMD Extensions:in one of the comments you posted above). For OpenBLAS you can't tell, but you can actually select which ones get dynamically selected at runtime - which is why I suggested theOPENBLAS_CORETYPEexperiment above. If it's an OpenBLAS Neoverse1-specific kernel, then there's a good chance you can reproduce the failure locally by doingexport OPENBLAS_CORETYPE=NEOVERSEN1before running the reproducer.theAeon commentedon Jul 28, 2025
Well, I can't reproduce that locally as the oryon chips (and the large majority of consumer facing arm chips that i'm aware of) don't have the SVE extension set that neoversen1 does.scratch that, neoversen1 doesn't actually have sve haha
theAeon commentedon Jul 28, 2025
If someone forces the CI to run with
OPENBLAS_CORETYPE=ARMV8, however, that would probably work.5 remaining items
MugundanMCW commentedon Jul 29, 2025
@theAeon I use the Qualcomm Snapdragon X-Elite chipset for testing SciPy.
theAeon commentedon Jul 29, 2025
so the same chip I'm on.
Bizarre.
bashtage commentedon Mar 30, 2026
I'm seeing segfaults on Windows ARM64 with float64 arrays in
np.linalg.invtoo.mattip commentedon Mar 30, 2026
@bashtage can you provide more details: what does numpy.show_runtime() show?
bashtage commentedon Mar 30, 2026
This is what I see on the CI runner:
bashtage commentedon Apr 1, 2026
I can add that we are also seeing failures on
solveon Windows-ARM64.mattip commentedon Jun 13, 2026
Maybe connected to #31618?
mattip commentedon Jul 5, 2026
Can someone with an appropriate machine check if this was fixed?
MugundanMCW commentedon Jul 5, 2026
Sure @mattip
chinazhangchao commentedon Sep 9, 2026
Hi @MugundanMCW , any updates on this?
bashtage commentedon Nov 4, 2026
I did a rather large exprimental session tonight using CI runners and Claude. What was found:
invis triggered by setting OPENBLAS_NUM_THREADS=1The full report is in the next post.
bashtage commentedon Nov 4, 2026
numpy.linalg crashes on Windows on ARM: findings from 2026-11-04
These experiments ran on GitHub Actions
windows-11-armrunners in arch PRs #1003 to #1007. None of these PRs is for merging.Important
In the OpenBLAS of numpy's
win_arm64wheels,np.linalg.invandnp.linalg.solvecrash only for 23×23 to 31×31 matrices, and only when OpenBLAS starts with 1 thread. The routine that crashes is LAPACK'sdgesv. Every numpy withwin_arm64wheels has the bug, from 2.3.0 to the current nightly. arch itself is fine. With 4 threads, or no limit, nothing crashes.Summary
invandsolve(1 or 3 right-hand sides). Neverdet,cholesky,qr,eigh,svd,lstsqormatmul.inv(np.eye(23))crashes.dgesv. Its parts,dgetrfthendgetrs, don't crash.win_arm64wheels: 2.3.0 to the nightly 2.6.0.dev0 (2026-11-03).-X faulthandler.Minimal reproducer
This exits with
0xC0000005(Windows fatal exception: access violation). WithoutOPENBLAS_NUM_THREADS, or with it set to 4, it runs fine.Setup
windows-11-arm, imagewindows-11-vs2026-arm6420261101.203.1ARMv8 (64-bit) Family 8 Model D49, MICROSOFT CORPORATION. Part 0xD49 is Neoverse N2. 4 cores.win-arm64)win_arm64wheels, and the nightly fromscientific-python-nightly-wheelsscipy-openblas0.3.34.dev,NO_AFFINITY ARMV8 MAX_THREADS=24, LP64, clang-cl 22.1.8openblas_get_corename()returnsARMV8. The build has ARMV8 kernels only.Findings
1. Calls and sizes (#1004)
All with
OPENBLAS_NUM_THREADS=1and numpy 2.5.4.inv, identity or random positive definite matrixsolve,bwith 1 or 3 columnsdet,cholesky,qr,eigh,svd,lstsqmatmul, matrix and vectorEach size was called 3 times. Every size that crashed also crashed when run alone, in a new process.
2. The routine:
dgesv(#1006)These calls go straight into numpy's own OpenBLAS (
numpy.libs/scipy_openblas-*.dll) withctypes.ctypescatches the access violation and reports its address.dgesv,nrhs1 or 3access violation reading 0x0000000000000024, every timedgetrfthendgetrson the same matrix, asdgesvdoesdgetrf,dgetrs,dgetri,dpotrfdtrsm,dlaswp,dgemm,dgemvNote
Reading address
0x24means a member of a struct is read through a null pointer. numpy'sinvandsolvecallgesv, anddetcalls onlygetrf, which fits the calls that crash.3. Threads (#1004, #1006)
What matters is the number of threads when OpenBLAS starts, not only when it's called.
OPENBLAS_NUM_THREADSat startopenblas_set_num_threadsbefore the callsdetnever hangs with 2 or 3 threads. The hang map covered sizes 1–40, and a call counted as hung after 15 s.4. numpy versions (#1005)
1 thread. Each row is the first or last release of a minor version with
win_arm64wheels.invsolveMAX_THREADS=4)The whole table is on Python 3.13. 2.5.4 and the nightly were also run on Python 3.14, with the same results. The bug isn't fixed in numpy's main branch. That answers the question left open on numpy#29442 since July.
5. What makes no difference (#1003, #1007)
scipy.linalg.inv,solve,lu_factor,lu_solveandcho_factor, and the wrappersdgesv,dgetrf,dgetrs,dgetri,dpotrf,dtrsm,dlaswp,dgemmanddgemv. numpy 2.4.6 bundles the same OpenBLAS version, and it does crash.-X faulthandler.OPENBLAS_CORETYPE:ARMV8,NEOVERSEN1andCORTEXA57change nothing.6. arch (#1003)
invinDynamicOLS._cov, of 23×23 to 30×30 matrices. 2 aresolvein the ADF and DFGLS lag search, on their first 23×23 system.win_arm64wheel, its compiled extensions load, and the univariate (13,198) and multiple comparison (771) tests pass.What this means for arch on Windows on ARM
Tip
Don't limit the BLAS threads on Windows on ARM. #1003 now runs the whole suite with no thread limit. It fails if any
*_NUM_THREADSvariable is set, or if numpy's OpenBLAS reports fewer than 2 threads. The jobs cover Python 3.13 and 3.14 with numba, and 3.15 without it. Python 3.12 can't be tested, because statsmodels haswin_arm64wheels only for 3.13 and later.win_arm64wheels)#1003 is now "CI: Test on Windows on ARM". It adds this job and release notes. The Azure pipeline and the wheel builds are restored, so the change against main is only the workflow and the release notes.
How the experiments ran
ci/github-actions/winarm_blas.pyis the same script in all four experiment PRs. It runs every call in a child process:start CALL Nbefore each call.einsum, which doesn't call BLAS. So the call under test is the only BLAS call.selftestcrashes at size 5 on purpose, which shows that crashes are found on ARM.A job takes 30–60 seconds. The first size map in #1003 started a process for every call and size, and allowed 900 s per hang. It hit the 2-thread hangs, ran for over an hour, and was cancelled at the 2-hour job limit.
PRs, runs and saved data
openblas_set_num_threadsAll job logs, results tables, saved crash matrices and copies of the numpy issues are in
reports/numpy-winarm64-linalg/in the release folder. A draft comment for numpy#29442 is ready, and nothing has been posted to numpy yet.Open questions
dgesvcrash whendgetrffollowed bydgetrsdoesn't? Inside OpenBLAS,dgesvis those two calls.bashtage commentedon Nov 4, 2026
It also appears that using the latest SciPy may be a viable workaround for projects that already depend on SciPy.
mattip commentedon Nov 5, 2026
One difference between SciPy and NumPy is that SciPy uses 32-bit interfaces (scipy-openblas32), NumPy uses 64-bit interfaces (scipy-openblas64).