Skip to content

Fix "numpy.dtype size changed" After a NumPy 2 Upgrade

Tested with: numpy 2.5.3 and 1.26.4, pandas 2.1.4 and 3.0.6, scikit-learn 1.3.2 and 1.9.1, scipy 1.11.4, 1.17.1 and 1.18.1, opencv-python-headless 4.8.1.78 and 5.0.0.93, pip 26.2.1, Python 3.12.3, Ubuntu 24.04, fresh venvs. Last run 2026-09-27.

TL;DR:
  1. Cause: a package with compiled extensions was built against NumPy 1.x and you now have NumPy 2. Check with python -c "import numpy; print(numpy.__version__)".
  2. Best fix: upgrade the package named in the traceback (pip install -U pandas, scikit-learn, scipy, opencv-python-headless). Every current release I tried imports cleanly on numpy 2.5.3.
  3. If you must keep the old package version: pip install "numpy<2". That installed 1.26.4 and the old packages imported again.
  4. Doesn't help: reinstalling the same package version with --force-reinstall --no-cache-dir. It fetches the identical wheel.
  5. Prevent it: install numpy-dependent packages in one pip install command (or one requirements file), then run pip check. Note that pip check missed the OpenCV case below.

You import pandas, scikit-learn, or another numpy-based library and the import dies inside a compiled module:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File ".../site-packages/pandas/__init__.py", line 46, in <module>
    from pandas.core.api import (
  File ".../site-packages/pandas/core/api.py", line 1, in <module>
    from pandas._libs import (
  File ".../site-packages/pandas/_libs/__init__.py", line 18, in <module>
    from pandas._libs.interval import Interval
  File "interval.pyx", line 1, in init pandas._libs.interval
ValueError: numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObject

That is pandas 2.1.4 on numpy 2.5.3. The two numbers are the size of numpy's dtype object: 96 bytes is what the extension was compiled with (NumPy 1.x headers), 88 is what the running NumPy 2 reports. In every run I did, the numbers were the same 96 and 88. Packages built a different way fail with different text for the same underlying problem, covered in the table below.


Reproduced: Each Error and the Fix That Worked

Setup: one fresh python3 -m venv per row, pip install --upgrade pip, the old package installed with numpy==1.26.4, then pip install "numpy>=2" (resolved to 2.5.3), then the import. The error column shows the last line printed.

What I ranExact errorFix that worked
pandas 2.1.4, numpy upgraded to 2.5.3, import pandasValueError: numpy.dtype size changed, may indicate binary incompatibility. Expected 96 from C header, got 88 from PyObjectpip install -U pandas (got 3.0.6, numpy stayed 2.5.3, import worked)
scikit-learn 1.3.2, numpy upgraded to 2.5.3, import sklearnSame ValueError, raised from sklearn/utils/murmurhash.pyxpip install "numpy<2" (got 1.26.4, import worked)
scipy 1.11.4, numpy upgraded to 2.5.3, import scipy.linalgMessage A module that was compiled using NumPy 1.x cannot be run in NumPy 2.5.3 as it may crash., then ImportError: numpy.core.multiarray failed to importpip install -U scipy (got 1.18.1, scipy.linalg.inv worked)
opencv-python-headless 4.8.1.78, numpy upgraded to 2.5.3, import cv2Same "compiled using NumPy 1.x" message, then AttributeError: _ARRAY_API not found, then ImportError: numpy.core.multiarray failed to importpip install -U opencv-python-headless (got 5.0.0.93, import worked)
pandas 2.1.4 broken as above, then pip install --force-reinstall --no-cache-dir --no-deps pandas==2.1.4Identical ValueError after the reinstallNone; the same version gives the same wheel. Change pandas or numpy instead.
pandas 2.1.4 installed, later a separate pip install scipypip installed scipy 1.18.1 and numpy 2.5.3; import pandas then gave the same ValueErrorInstall together: pip install "pandas==2.1.4" "scipy>=1.14" chose scipy 1.17.1 with numpy 1.26.4 and both imported

Which combinations pip allowed:

  • pandas 2.1.4, scikit-learn 1.3.2 and scipy 1.11.4 declare an upper bound on numpy (numpy<2, numpy<2.0 and numpy<1.28.0). Pip still upgraded numpy when asked. For pandas and scipy it printed ERROR: pip's dependency resolver does not currently take into account all the packages that are installed with the conflicting requirement, and ended with Successfully installed numpy-2.5.3. The install "succeeded"; the import failed.
  • opencv-python-headless 4.8.1.78 has no upper bound. Pip upgraded numpy without any warning and pip check printed No broken requirements found. while import cv2 was failing.

The reverse direction is different. Packages built for NumPy 2 are meant to also load on NumPy 1.x. With numpy forced down to 1.26.4 (--no-deps), pandas 3.0.6 and scipy 1.18.1 both imported and computed correctly; scipy only printed UserWarning: A NumPy version >=2.0.0 and <2.8.0 is required for this version of SciPy (detected version 1.26.4). scikit-learn 1.9.1 failed, but with a plain Python error, AttributeError: module 'numpy' has no attribute 'long', not the dtype size error. So "dtype size changed" points at an old package on a new numpy, not the other way around.


What's actually happening

Packages such as pandas, scikit-learn and scipy ship compiled C/Cython extensions. When a wheel is built, it records numpy's C struct layout from the numpy version it was compiled against. Cython checks the size of numpy's dtype type when the module loads, and NumPy 2 changed that layout, so a wheel built against 1.x headers sees 88 bytes where it expected 96 and refuses to load. Extensions built with other tools (scipy's Fortran wrappers, OpenCV's bindings) hit NumPy 2's own import check instead, which prints the "compiled using NumPy 1.x" message.

Neither wheel is damaged; the combination is what fails. The most common ways to end up there:

  • You ran pip install -U numpy (or something that requires numpy 2) without upgrading the older packages that sit on top of it.
  • Packages were added in separate pip install commands, as in the scipy row above. Each command is resolved on its own, and a later one can move numpy under an earlier one.
  • A requirements file pins an old pandas, scikit-learn or OpenCV but leaves numpy unpinned. For packages without a numpy upper bound, pip will happily pick numpy 2.

Step 1: find the package with the old build

The last frames of the traceback name the compiled module: pandas/_libs/interval.pyx, sklearn/utils/murmurhash.pyx, scipy/linalg/blas.py or cv2/__init__.py in the runs above. Then check the installed versions and what pip thinks of them:

python -c "import numpy; print(numpy.__version__)"
pip list | grep -iE "^(numpy|pandas|scipy|scikit-learn|opencv)"
pip check

For the broken pandas venv, pip check printed:

pandas 2.1.4 has requirement numpy<2,>=1.26.0; python_version >= "3.12", but you have numpy 2.5.3.

pip show pandas is less useful here: its Requires: line lists numpy without any version bounds. To see the actual numpy range a package declares:

python -c "import importlib.metadata as m; print([r for r in m.requires('scipy') if 'numpy' in r])"

For scipy 1.17.1 that printed ['numpy<2.7,>=1.26.4', ...]. If pip check is clean but the import still fails (the OpenCV case), go by the traceback.


Step 2: the fix

Upgrade the package, keep NumPy 2

pip install -U pandas          # or scikit-learn, scipy, opencv-python-headless
python -c "import pandas"      # confirm

This is the fix to prefer. pandas 3.0.6, scipy 1.18.1 and opencv-python-headless 5.0.0.93 all imported on numpy 2.5.3, and pip check came back clean in the pandas and scipy venvs. Upgrading is a larger version jump in some cases (pandas 2.1 to 3.0, OpenCV 4 to 5), so run your tests afterwards.

Keep the old package, downgrade NumPy

pip install "numpy<2"

On Python 3.12 this installed numpy 1.26.4, and scikit-learn 1.3.2 imported again with pip check clean. Use this when you can't upgrade the package yet, for example to reproduce an old result. Pin it in your requirements so the next install doesn't move numpy back.

What doesn't fix it

pip install --force-reinstall --no-cache-dir pandas==2.1.4 downloads the same wheel that was built against NumPy 1.x, so the error is unchanged. (Without a version, pip install --force-reinstall pandas may "work", but only because it installs a newer pandas.)

Install the stack in one pass

python -m venv .venv --clear
source .venv/bin/activate
pip install -r requirements.txt    # one resolution for numpy and everything that uses it
pip check

One resolution lets pip see every numpy bound at once. In the test above, pip install "pandas==2.1.4" "scipy>=1.14" in one command picked scipy 1.17.1 (the newest scipy that still allows numpy 1.26) and numpy 1.26.4, and both imported. The same two packages installed in separate commands left pandas broken.


Docker

Each RUN pip install line is a separate pip command, so it behaves like the separate-install row above: a later layer can upgrade numpy under a package installed in an earlier layer. Put numpy and everything that depends on it in one requirements file and one RUN:

# Avoid: an old pandas in one layer, something needing numpy 2 in a later one
# RUN pip install pandas==2.1.4
# RUN pip install scipy

# Prefer: one resolution, then fail the build if the environment is inconsistent
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt && pip check

pip check in the build turns the pandas, scikit-learn and scipy cases into a build failure. It would not catch the OpenCV case, so a one-line python -c "import cv2" in the build is worth adding if you use it. I didn't run these inside Docker for this article; the behaviour shown is pip's, which is the same in a container.


Conda and pip together

The same rule applies in conda environments: numpy and the packages compiled against it should come from one resolver pass. conda install numpy followed by pip install of an old pandas wheel is two separate resolutions, just like the separate-install row above. If you use conda, install the numeric stack through conda in one command (conda install -c conda-forge numpy pandas scipy scikit-learn). I didn't test conda for this article.


Confirming it's fixed

python -c "import numpy, pandas, scipy.linalg, sklearn; print(numpy.__version__, pandas.__version__)"
pip check

This error is raised at import time (as a ValueError or ImportError), so import each affected package once after the fix. pip check is a useful second signal but, as the OpenCV row shows, not a complete one.