Fix
Getting Started With Python Excel AutomationDeep dive

Fix "Missing optional dependency 'openpyxl'" in pandas

pandas reads and writes Excel through separate engine packages, and the error means the engine is not importable from the Python that runs your code. Find which interpreter is running, install into that one, and handle the version-too-old variant.

The first pd.read_excel() in a fresh environment often ends like this:

Text
ImportError: Missing optional dependency 'openpyxl'.  Use pip or conda to install openpyxl.

In pandas 3 the wording is slightly different — ImportError: `Import openpyxl` failed. Use pip or conda to install the openpyxl package. — but the meaning is the same. pandas does not read or write .xlsx files itself; it hands them to an engine package, and that package could not be imported by the Python process running your code. The fix is almost always a one-line install, but where you install it is the part that goes wrong. This guide, part of Troubleshooting Common Python Excel Errors, finds the right interpreter and fixes each variant of the error.

How pandas finds an Excel engine read_excel picks an engine from the file extension, openpyxl for xlsx, then tries to import that package in the running Python. If the package is not installed in that interpreter, pandas raises the missing optional dependency ImportError; if it is installed but too old, it raises a minimum-version error. read_excel("x.xlsx") engine from extension import openpyxl in this interpreter Not found Missing optional dependency Too old requires version 3.1.5 or newer the error is about the interpreter running your code, not about your machine as a whole

Step 1 — Find out which Python is running

Before installing anything, ask the failing code which interpreter it is running under. Put these lines at the top of the script or in a notebook cell:

Python
import sys
print(sys.executable)
print(sys.version.split()[0])

The path is the truth. It might be a project's .venv, a conda environment, the Python that shipped with an IDE, or the system Python — and it is often not the one your terminal's pip belongs to. Every fix below installs into that path.

Step 2 — Install with that interpreter

Running pip by name uses whichever pip comes first on your PATH, which may belong to another Python. Run pip through the interpreter instead, so the package lands where the code will look for it:

Bash
# use the exact path printed by sys.executable
/path/to/python -m pip install openpyxl

# or, in an activated virtual environment
python -m pip install openpyxl

On Windows the equivalent is py -m pip install openpyxl for the default launcher Python, or the full path to python.exe inside the virtual environment. If you use conda, conda install openpyxl in the activated environment works too — but do not mix conda and pip for the same package in one environment.

Step 3 — Jupyter notebooks: install into the kernel

Notebooks add a layer: the notebook server and the kernel can be different Pythons, so !pip install openpyxl in a cell may install into the wrong one. The %pip magic always targets the running kernel:

Text
%pip install openpyxl

Then restart the kernel — a running Python process does not pick up packages installed after it started importing. If the error persists, the notebook is using a kernel from another environment; choose the right one from the kernel menu, or register your environment as a kernel with python -m ipykernel install --user --name myproject.

Where to install the missing engine If the code runs as a script in a virtual environment, activate it and use python -m pip. If it runs in Jupyter, use percent pip in a cell and restart the kernel. If it runs inside an IDE, check which interpreter the IDE uses and install into that one. If it runs on a server or in Docker, add the package to requirements and rebuild. Where does the failing code run? a terminal script python -m pip in the active venv Jupyter %pip install then restart the kernel an IDE IDE interpreter install into that path server or Docker requirements file rebuild the image

Step 4 — IDEs pick their own interpreter

VS Code, PyCharm and other editors run code with the interpreter selected in the project settings, which may differ from the one in your terminal. The status bar (VS Code) or Settings → Project → Python Interpreter (PyCharm) shows which. Either select the environment where openpyxl is installed, or install openpyxl into the selected one using its own package manager panel. The sys.executable check from Step 1 settles any doubt in seconds.

Step 5 — The version is too old

A different message means openpyxl is present but older than your pandas supports:

Text
ImportError: Pandas requires version '3.1.5' or newer of 'openpyxl' (version '3.0.10' currently installed).

Upgrade in the same interpreter:

Bash
python -m pip install --upgrade openpyxl

pandas keeps a table of minimum versions for every optional dependency, and each pandas release raises some of them. You can see what the installed pandas expects, and what you have, without triggering the error:

Python
import importlib.metadata as md

import pandas as pd
from pandas.compat._optional import VERSIONS

print("pandas", pd.__version__)
for package, module in [("openpyxl", "openpyxl"), ("xlsxwriter", "xlsxwriter"),
                        ("xlrd", "xlrd"), ("pyxlsb", "pyxlsb"),
                        ("odfpy", "odfpy"), ("python-calamine", "python-calamine")]:
    try:
        installed = md.version(package)
    except md.PackageNotFoundError:
        installed = "not installed"
    print(f"{package:16} needs >= {VERSIONS.get(module, '?'):8} installed: {installed}")

pandas.compat._optional is an internal module, so treat the listing as a diagnostic rather than something to build on — but it answers "which version do I need?" exactly for the pandas you have.

Step 6 — Other formats need other engines

openpyxl covers .xlsx and .xlsm. Other formats have their own engines, each with its own version of this error:

The engine package each Excel format needs in pandas xlsx and xlsm need openpyxl for reading, or xlsxwriter or openpyxl for writing. Legacy xls needs xlrd for reading. xlsb needs pyxlsb or python-calamine. ods needs odfpy. python-calamine reads all of these formats. Read Write .xlsx / .xlsm openpyxl or python-calamine openpyxl or xlsxwriter .xls (97-2003) xlrd or python-calamine .xlsb pyxlsb or python-calamine .ods odfpy or python-calamine odfpy

A project that reads assorted inputs can install python-calamine once and pass engine="calamine" to read every format, which also happens to be the fastest option; see Speed Up pandas Excel Reads with the calamine Engine. Engine choice in general is covered in Pick an Excel Engine for .xlsx, .xlsm, .xls, .xlsb and .ods.

Step 7 — Make it impossible for the next person

Once fixed on your machine, record the dependency so it cannot go missing again. Declare the engines your code uses next to pandas, and pin versions that you have tested together:

Text
# requirements.txt
pandas==3.0.6
openpyxl==3.1.5
xlsxwriter==3.2.9
python-calamine==0.8.2

A scheduled job, a Docker image or a colleague's checkout then installs everything in one step, and a CI run fails loudly if a dependency is missing instead of the error surfacing at 6 a.m. Checking imports at the start of a job — the loop in Step 5, with raise instead of print — turns a missing engine into a clear failure before any work is done. Packaging a whole Excel script so it runs elsewhere is covered in Testing and Packaging Excel Automation Scripts.

Step 8 — Fail fast at the start of a job

For a scheduled job, the worst time to discover a missing engine is halfway through, after files have been moved or emails half-sent. Check every engine the job needs before doing anything, and stop with one clear message that names the interpreter:

Python
import importlib
import sys

REQUIRED = {"openpyxl": "read and write .xlsx", "xlsxwriter": "formatted output"}

def check_engines(required: dict[str, str]) -> None:
    missing = []
    for module, purpose in required.items():
        try:
            importlib.import_module(module)
        except ImportError:
            missing.append(f"{module} ({purpose})")
    if missing:
        raise SystemExit(
            f"Missing packages for {sys.executable}: {', '.join(missing)}. "
            f"Install with: {sys.executable} -m pip install {' '.join(m.split()[0] for m in missing)}"
        )

check_engines(REQUIRED)
print("engines OK")

The message includes the exact command to run, with the exact interpreter path, which turns a confusing traceback in a log into a fix anyone on the team can apply. Call it as the first line of main(), before logging in anywhere or touching any file.

Common pitfalls

  • pip and python from different installations. The most common cause. Always use python -m pip.
  • Not restarting. A running notebook kernel or interactive session does not see packages installed after it started. Restart it.
  • Installing pandas[excel] and assuming everything is covered. The excel extra installs the usual engines, but a pinned or older environment may still lack one; check with the listing above.
  • A broken or partial install. An interrupted install can leave a package directory without its metadata, and imports then fail in odd ways. python -m pip install --force-reinstall openpyxl repairs it.
  • Naming a file openpyxl.py. A script named after the package shadows it, and imports fail with confusing errors. Rename the file and delete any __pycache__.

Conclusion

"Missing optional dependency 'openpyxl'" means the engine pandas needs is not importable from the interpreter running your code. Print sys.executable, install with that interpreter via python -m pip (or %pip in Jupyter, then restart), point your IDE at the environment you installed into, upgrade when pandas asks for a newer version, and install the right engine for .xls, .xlsb and .ods files. Record the engines in your requirements so the error does not come back.

Frequently asked questions

Why does pandas need openpyxl to read Excel? pandas does not parse Excel files itself. It hands .xlsx files to an engine package — openpyxl by default — and treats that package as an optional dependency, so installing pandas alone does not install it.

I installed openpyxl but still get the error. Why? It was installed into a different Python than the one running your code — a different virtual environment, a different Jupyter kernel, or the system Python. Install with the same interpreter using python -m pip, or %pip inside the notebook.

What does "Pandas requires version '3.1.5' or newer of 'openpyxl'" mean? openpyxl is installed but older than your pandas version supports. Upgrade it with python -m pip install --upgrade openpyxl.

Which package do I need for .xls, .xlsb or .ods files? xlrd for legacy .xls, pyxlsb or python-calamine for .xlsb, and odfpy for .ods. python-calamine reads all of them and .xlsx as well.

More on errors & fixes

More on errors & fixes →