How to Install and Run Pandas in CI Reliably
Pandas installs from a wheel in seconds on mainstream platforms - the CI pain is usually a missing wheel on a new Python, or an out-of-memory kill on a large DataFrame job.
Pandas depends on NumPy and ships manylinux wheels, so installs are normally trivial. Two things bite in CI: a too-new Python or musl image with no wheel (forcing a slow source build), and memory pressure when a job loads a large dataset into a DataFrame and gets OOM-killed (exit 137).
Why it fails in CI
Install-time, the failure mirrors NumPy: no wheel for the interpreter means a source build that needs a compiler and is slow. Run-time, Pandas holds entire DataFrames in memory; a big read on a small runner triggers the kernel OOM killer and the step dies with exit 137.
No matching distribution found for pandason a brand-new Python or Alpine.Failed building wheel for pandaswhen compiling its Cython extensions from source.- Step killed with exit 137 - the kernel OOM-killed the process on a large DataFrame.
Install it reliably
Keep the wheel by using a glibc base image and a Python version Pandas ships wheels for, and force-binary so a missing wheel fails fast. For memory, give the job a bigger runner or stream data in chunks rather than loading it all at once.
# Force the prebuilt wheel
pip install --only-binary=:all: pandas
# Read large data in chunks to bound memory
# for chunk in pd.read_csv('big.csv', chunksize=100_000): process(chunk)Cache & speed
Cache ~/.cache/pip so the Pandas + NumPy wheels are reused across runs. For data-heavy test jobs, prefer a runner sized to the dataset over fighting OOM with retries.
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-pandas-${{ hashFiles('requirements*.txt') }}Common errors
| Error | Cause | Fix |
|---|---|---|
| No matching distribution found for pandas | No wheel for this Python/musl | Pin a supported Python; use glibc |
| Failed building wheel for pandas | Source build (Cython) | Force --only-binary |
| Exit 137 on a large read | OOM-killed | Bigger runner or chunked reads |
| MemoryError | DataFrame too large | Stream/chunk, use dtypes, or downsample |
Key takeaways
- Pandas has wheels - keep the wheel path with glibc + a supported Python.
- Exit 137 means OOM: size the runner or chunk the data.
- Force --only-binary so a missing wheel fails fast.