Fix Camelot Import Error on Linux

Importing camelot on a fresh Linux environment raises one of three errors. The exact message depends on which system dependency is missing:

ImportError: No module named 'camelot'
ModuleNotFoundError: No module named 'cv2'
OSError: ghostscript not found on PATH

All three errors come from the same root cause: camelot's lattice mode requires two system-level binaries — Ghostscript and OpenCV — that are not installed by a plain pip install camelot-py.

Root Cause

camelot-py is published in two variants on PyPI:

PackageWhat it includesWhen it fails
camelot-pyCore library onlyLattice mode crashes — no OpenCV
camelot-py[cv]Core + OpenCV bindingsWorks if Ghostscript binary is also installed

The cv2 (OpenCV) module handles image processing for lattice-mode table detection. Ghostscript is called as a subprocess to convert PDFs to intermediate images before processing. Neither ships inside a wheel — they are system-level dependencies. This is the same class of "external binary not on PATH" failure that trips up tabula-py (which needs a JVM) and Tesseract (which needs the tesseract binary); the diagnostic pattern below applies to all three.

From error message to fix: the three camelot dependency failures Three lanes. ImportError No module 'camelot' maps to the missing camelot-py Python package, fixed by pip install camelot-py with the cv extra. ModuleNotFoundError cv2 maps to the missing OpenCV binary wheel, fixed by pip install opencv-python-headless. OSError ghostscript not found maps to the missing Ghostscript system binary, fixed by apt-get install ghostscript. All three fixes converge on a working camelot.read_pdf call. Error you see Missing piece Apply this fix ImportError No module 'camelot' camelot-py Python package pip install "camelot-py[cv]" ModuleNotFoundError No module 'cv2' OpenCV (cv2) binary wheel pip install opencv-python-headless OSError ghostscript not found Ghostscript system binary sudo apt-get install ghostscript camelot.read_pdf() works all dependencies resolved

Minimal Diagnostic

Run this before attempting any fix to confirm which component is missing:

# No pip install needed — this only tests imports
def diagnose_camelot() -> dict:
    """Check which camelot dependencies are present."""
    status = {}

    try:
        import camelot
        status["camelot"] = camelot.__version__
    except ImportError as e:
        status["camelot"] = f"MISSING: {e}"

    try:
        import cv2
        status["cv2"] = cv2.__version__
    except ImportError as e:
        status["cv2"] = f"MISSING: {e}"

    import shutil
    gs = shutil.which("ghostscript") or shutil.which("gs")
    status["ghostscript_binary"] = gs or "NOT FOUND"

    return status

if __name__ == "__main__":
    import pprint
    pprint.pprint(diagnose_camelot())

Expected healthy output:

{'camelot': '0.11.0',
 'cv2': '4.9.0',
 'ghostscript_binary': '/usr/bin/ghostscript'}

Any MISSING or NOT FOUND value maps directly to the fix below.

Fix: Install Ghostscript and camelot-pycv

Run the following in order. Do not skip steps — Ghostscript must be present before the Python install or camelot's post-install check will fail.

# Step 1: Install Ghostscript system binary
sudo apt-get update && sudo apt-get install -y ghostscript

# Step 2: Verify the binary is accessible
gs --version
# Expected: 9.x or 10.x

# Step 3: Install camelot with the cv extra (includes OpenCV)
pip install "camelot-py[cv]"

# Step 4: Confirm no import errors
python -c "import camelot; print(camelot.__version__)"

The [cv] extra installs opencv-python-headless as a dependency. This is the headless variant — it has no GUI dependencies, which is correct for server environments.

Variant Fix 1: ModuleNotFoundError: No module named 'cv2'

This error means camelot is installed but the [cv] extra was not included. The package was installed as bare camelot-py:

# Check what is installed
pip show camelot-py | grep -i requires

If cv2 is not in the requirements list, reinstall with the extra:

pip uninstall camelot-py -y
pip install "camelot-py[cv]"

If you are in a virtualenv where opencv-python is already installed (not the headless variant), the cv2 import may still fail due to missing GUI libraries (libGL.so.1):

# Install the headless variant to avoid X11 / display dependencies
pip uninstall opencv-python -y
pip install opencv-python-headless

# Or install the missing system lib directly:
sudo apt-get install -y libgl1

Variant Fix 2: OSError: ghostscript not found at Runtime

This error appears after a successful import camelot — it surfaces when camelot.read_pdf() is first called:

OSError: ghostscript not found on PATH. Please install ghostscript.

The binary is either not installed or not on the PATH seen by the Python process:

# Confirm the binary name — Debian/Ubuntu uses 'ghostscript', others use 'gs'
which ghostscript || which gs

# If missing:
sudo apt-get install -y ghostscript

# If present but not on PATH (e.g., in a restricted shell):
export PATH="$PATH:/usr/bin"
python -c "import camelot; camelot.read_pdf('test.pdf', pages='1', flavor='lattice')"

If running inside a Docker container or CI environment without apt access, use the ghostscript Python binding as a fallback — but note this is slower than the system binary:

pip install ghostscript

Then verify camelot can find it:

# pip install ghostscript camelot-py[cv]
import ghostscript   # exercises the binding
import camelot
print("All dependencies resolved:", camelot.__version__)

Variant Fix 3: ImportError for tkinter on Headless Servers

Some older camelot-py versions imported tkinter at module load time. On headless servers (no display), this raises:

_tkinter.TclError: no display name and no $DISPLAY environment variable

Fix: upgrade camelot to 0.10.1 or later, which dropped the hard tkinter dependency:

pip install --upgrade "camelot-py[cv]"
python -c "import camelot; print(camelot.__version__)"

If upgrading is not possible, set a dummy display before importing:

# Temporary workaround only — upgrade is the proper fix
DISPLAY=:99 python your_script.py

Variant Fix 4: Ghostscript Version Conflict

Camelot calls Ghostscript via the command-line API using version-specific flag sets. If you have a very new Ghostscript (11.x) installed and a pinned older camelot, the subprocess call may fail with:

subprocess.CalledProcessError: Command '['gs', ...]' returned non-zero exit status 1

Check the installed version and whether camelot supports it:

gs --version
pip show camelot-py | grep Version

If Ghostscript is 11.x and camelot is below 0.11, upgrade camelot first:

pip install --upgrade "camelot-py[cv]"

If you cannot upgrade camelot (pinned by another dependency), install an older Ghostscript alongside the current one using the Ghostscript release tarballs at ghostscript.com, then point camelot at it by setting the GS_PROG environment variable:

export GS_PROG=/usr/local/bin/gs-9.56
python your_script.py

Environment-Specific Notes

Docker

Minimal Docker images (Alpine, python:3.x-slim) do not include Ghostscript. Add the following to your Dockerfile before the pip install step:

# Debian-based image
RUN apt-get update && apt-get install -y --no-install-recommends \
    ghostscript \
    libsm6 \
    libxext6 \
    && rm -rf /var/lib/apt/lists/*

RUN pip install "camelot-py[cv]"

libsm6 and libxext6 are required by OpenCV on Debian even in headless mode.

GitHub Actions

Add the system install step before the Python setup action:

- name: Install system dependencies
  run: sudo apt-get update && sudo apt-get install -y ghostscript libsm6 libxext6

- name: Install Python dependencies
  run: pip install "camelot-py[cv]" pandas

Red Hat / CentOS / Fedora

Replace apt-get with dnf:

sudo dnf install -y ghostscript opencv
pip install "camelot-py[cv]"

Note that opencv on dnf installs the C++ library but not the Python binding — the [cv] extra still handles the Python side.

Only lattice needs the system binaries Lattice mode rasterises the page, so it requires Ghostscript and OpenCV. Stream mode works from the text layer alone and needs neither. A pipeline that only uses stream can therefore run on a slim image with no apt packages at all, which is worth knowing before adding two hundred megabytes to a container. System dependencies by flavour flavor="lattice" Ghostscript + OpenCV required the page is rasterised to find lines flavor="stream" no system binaries at all works from the text layer

Troubleshooting Table

A quick reference for matching the exact error text to the right fix:

Error messageComponent missingFix command
ImportError: No module named 'camelot'camelot not installedpip install "camelot-py[cv]"
ModuleNotFoundError: No module named 'cv2'OpenCV not installedpip install opencv-python-headless
OSError: ghostscript not found on PATHGhostscript binary missingsudo apt-get install ghostscript
OSError: ghostscript not found on PATHBinary not on Python's PATHexport PATH="$PATH:/usr/bin"
_tkinter.TclError: no display nameOld camelot with tkinter deppip install --upgrade "camelot-py[cv]"
libGL.so.1: cannot open shared object fileNon-headless OpenCV on serverpip install opencv-python-headless
subprocess.CalledProcessError on gs callGhostscript version mismatchpip install --upgrade "camelot-py[cv]"

Confirming the Correct camelot Package Is Installed

There are three similarly named packages on PyPI: camelot-py, camelot (an unrelated project), and camelot-py[cv]. Installing the wrong one is a common mistake:

# Confirm camelot-py is installed, not the unrelated 'camelot' package
pip show camelot-py

# The output should include:
# Name: camelot-py
# ...
# Requires: chardet, click, numpy, openpyxl, pandas, pdfminer.six, pypdf2, tabulate
# (plus opencv-python-headless when installed with [cv])

# If you see 'Name: camelot' without 'py', you have the wrong package:
pip uninstall camelot -y
pip install "camelot-py[cv]"

After a correct install, the import path is always import camelot — both packages use the same name, which is why the error message alone is not enough to distinguish them.

Three similarly named packages Three PyPI names. The package called camelot is an unrelated project and installing it gives an import that fails in confusing ways. The package camelot-py is the right library but omits OpenCV. The camelot-py with the cv extra is the one to install. All three expose the same import name, which is why the error message alone cannot tell them apart. All three import as "camelot" camelot unrelated project wrong package entirely camelot-py right library, no OpenCV lattice will fail camelot-py[cv] the one you want pulls in headless OpenCV

Verification

After applying all fixes, run the full smoke test:

# pip install "camelot-py[cv]" pandas
from pathlib import Path
import camelot
import pandas as pd

def smoke_test(pdf_path: Path) -> None:
    """Verify camelot can open a PDF and return at least one table."""
    if not pdf_path.exists():
        raise FileNotFoundError(f"Test PDF not found: {pdf_path}")
    try:
        tables = camelot.read_pdf(
            str(pdf_path),
            pages="1",
            flavor="lattice",
        )
    except Exception as e:
        raise RuntimeError(f"camelot.read_pdf failed: {e}") from e

    assert tables.n >= 0, "camelot.read_pdf ran without error"
    print(f"camelot {camelot.__version__} OK — found {tables.n} table(s) on page 1")

if __name__ == "__main__":
    # Use any single-page PDF with a bordered table, or any PDF to test import
    smoke_test(Path("data/sample.pdf"))

A clean run with no ImportError, no OSError, and a printed version confirms all dependencies are wired correctly. Each element of tables exposes a .df attribute that is a plain pandas DataFrame, so a successful smoke test means the extraction pipeline is ready. For the full extraction workflow once camelot is working, continue with Extracting Tables from PDFs; to weigh camelot against the alternatives, see comparing PDF table extraction libraries.

FAQ

What is the difference between camelot-py and camelot-py[cv]?camelot-py installs only the core Python library. The [cv] extra additionally pulls in opencv-python-headless, which lattice mode needs for image processing. On a server you almost always want camelot-py[cv]; installing bare camelot-py is the single most common cause of the No module named 'cv2' error.

Do I need Ghostscript for stream mode, or only lattice? Ghostscript is required for lattice mode (flavor='lattice'), because camelot rasterizes the page to detect ruling lines. Stream mode (flavor='stream') relies on text-coordinate whitespace and does not shell out to Ghostscript, so a stream-only workflow can run without the binary — but installing it anyway avoids surprises when you switch flavors.

Why does camelot work on my laptop but fail in Docker or CI? Minimal base images (python:3.x-slim, Alpine) omit Ghostscript and the OpenCV system libraries (libGL.so.1, libsm6, libxext6). Your laptop already has them from other software. Add an explicit apt-get install step for ghostscript libsm6 libxext6 before pip install, as shown in the Docker and GitHub Actions notes above.

Should I install opencv-python or opencv-python-headless? Use opencv-python-headless on any machine without a display (servers, containers, CI). The non-headless build links against X11/GUI libraries, so importing cv2 fails with libGL.so.1: cannot open shared object file on a headless host. The [cv] extra already selects the headless variant.

Which Ghostscript version does camelot need? Any 9.x or 10.x release works with current camelot (0.11+). A very new Ghostscript (11.x) paired with an old pinned camelot can raise subprocess.CalledProcessError on the gs call — upgrade camelot, or pin an older Ghostscript and point at it with GS_PROG, as covered in Variant Fix 4.

Part of Extracting Tables from PDFs.

/html>