2025, Oct 28 17:00

Resolve 'No module named _ctypes' for tflite_runtime on Raspberry Pi 5 (Bookworm) with Edge TPU

Fix tflite_runtime import on Raspberry Pi Bookworm: resolve No module named _ctypes by installing libffi-dev and rebuilding Python 3.9 with pyenv for Edge TPU.

When running TensorFlow Lite with an Edge TPU on Raspberry Pi OS Bookworm 12, a seemingly innocuous import can derail the whole setup. If Python throws “No module named '_ctypes'” on a Raspberry Pi 5 while trying to load tflite_runtime, the issue isn’t with TFLite at all—it’s a missing dependency from when Python itself was compiled.

Reproducing the failure

The scenario appears when pycoral limits Python support to 3.6–3.9, so Python 3.9 is built via pyenv. TFLite is then tested with a minimal interpreter script using the Edge TPU delegate. The import fails before the model even loads.

#!/usr/bin/env python3
from pathlib import Path
from tflite_runtime.interpreter import Interpreter as TflInterpreter, load_delegate as get_delegate

model_file = Path("/home/USER/models/efficientdet_lite1_int8_edgetpu.tflite")
edge_tpu = get_delegate("/usr/lib/aarch64-linux-gnu/libedgetpu.so.1")
engine = TflInterpreter(model_path=str(model_file), experimental_delegates=[edge_tpu])
engine.allocate_tensors()
print("allocate_tensors completed; interpreter is ready")

The crash shows up right at import time and looks like this:

ModuleNotFoundError: No module named '_ctypes'

What actually went wrong

The error indicates that Python’s _ctypes module wasn’t built. On Pi OS Bookworm 64-bit, this typically happens if libffi-dev was not present when compiling Python via pyenv. Without libffi-dev available at build time, Python skips building _ctypes, and any library depending on ctypes immediately breaks. This is especially visible with tflite_runtime, which imports ctypes early.

Complicating matters, libffi-dev may not appear in apt on this setup. Searching with apt-cache yields nothing, and apt reports no installation candidate, even with Debian and Raspberry Pi repositories configured.

Fixing the environment and rebuilding Python

The reliable path forward is to bring in libffi-dev manually and then rebuild Python so that _ctypes is compiled correctly. First, obtain the libffi-dev .deb package from the Debian site and install it. With that in place, re-install Python 3.9 via pyenv, making sure the build process can find headers and libraries in /usr/local.

CFLAGS="-I/usr/local/include" \
LDFLAGS="-L/usr/local/lib" \
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" \
pyenv install 3.9.18

After the rebuild, the missing _ctypes module should be resolved, and tflite_runtime can import successfully.

Verifying the setup

Re-run the same test to confirm the interpreter initializes with the Edge TPU delegate and allocates tensors without errors.

#!/usr/bin/env python3
from pathlib import Path
from tflite_runtime.interpreter import Interpreter as TflInterpreter, load_delegate as get_delegate

model_file = Path("/home/USER/models/efficientdet_lite1_int8_edgetpu.tflite")
edge_tpu = get_delegate("/usr/lib/aarch64-linux-gnu/libedgetpu.so.1")
engine = TflInterpreter(model_path=str(model_file), experimental_delegates=[edge_tpu])
engine.allocate_tensors()
print("allocate_tensors completed; interpreter is ready")

Why this matters

On developer boards like Raspberry Pi 5, language runtimes are often custom-built to meet library constraints. If a core module like _ctypes is missing, entire stacks fall over in non-obvious ways. For workloads involving tflite_runtime and Coral Edge TPU, that failure point sits right at import time, so diagnosing it quickly saves hours of debugging the wrong layer.

Takeaways

When Python is built with pyenv for compatibility with packages such as pycoral, ensure that libffi-dev is available at build time. If apt can’t find libffi-dev on Pi OS Bookworm 64-bit, fetch the .deb from the Debian site, install it, and rebuild Python with include and library paths exposed. Once _ctypes is present, the tflite_runtime import issue goes away, and the Edge TPU delegate can be loaded as expected.

The article is based on a question from StackOverflow by mightye77 and an answer by Sambrown02.