2025, Oct 16 07:00
Resolve igl.tet_tet_adjacency AttributeError in libigl: quick fix with igl==2.2.0 and stable setup tips
Hit AttributeError: igl.tet_tet_adjacency in libigl? Learn why bindings changed, how to fix by pinning igl==2.2.0, and prevent breakage with version control.
Running a legacy research script and suddenly hitting AttributeError: module 'igl' has no attribute 'tet_tet_adjacency can be maddening. This specific failure shows up when executing the fracture-modes example, where the mesh explosion step depends on libigl’s Python bindings. The code used to work, but on a newer environment the attribute is gone. The root of the breakage is a bindings change in libigl rather than a bug in the script itself.
Reproducing the failure
The error surfaces at the point where tetrahedral adjacency is requested from libigl. The call path ends at a single line like this one, which computes adjacency for a tetrahedral mesh.
import igl
def make_exploded_mesh(pts, cells):
    neigh, neigh_ids = igl.tet_tet_adjacency(cells)
    return neigh, neigh_ids
# Somewhere upstream the function is invoked with tetrahedra indices
# make_exploded_mesh(vertices, tetrahedra)
On environments where the bindings no longer expose tet_tet_adjacency, importing igl succeeds, but calling igl.tet_tet_adjacency raises AttributeError. Users reported seeing this with libigl 2.6.1.
What is actually happening
The issue is tied to the libigl Python bindings, not to the geometry code in the repository. The repository is several years old and does not pin a specific version of igl, so installing or updating dependencies can silently pick up a newer binding where tet_tet_adjacency is not available under the same name or location. Since the script relies on that symbol exactly as written, the attribute lookup fails at runtime.
Fix that works right now
The quickest path is to roll back the igl package to a release where the function is present. A confirmed working choice is igl==2.2.0. Pinning that version restores the original behavior without changing any of the project’s code.
# requirements.txt
igl==2.2.0
After pinning, reinstall dependencies and rerun the example. The same Python call to igl.tet_tet_adjacency should succeed, and the fracture mode computation proceeds as before.
If you want a more durable setup
The more thorough, albeit time-consuming, path is to review the libigl changelog and related issues or PRs to learn whether the function was removed, renamed, or relocated in the bindings, and then pin the exact compatible version for this project. This prevents future breakage when setting up fresh environments and aligns expectations for anyone else running the code.
Why this matters
Scientific and graphics tooling often depends on native libraries with Python bindings, and those bindings evolve. When a repository is older and dependencies are not pinned, a single update can remove or rename APIs and break critical paths at runtime. Understanding that the failure stems from a moving dependency, not the project logic, helps you focus on environment control instead of refactoring the algorithm.
Wrap-up and practical advice
If you encounter AttributeError on igl.tet_tet_adjacency while running the fracture-modes example, treat it as a bindings mismatch. Revert igl to an older release known to expose that function; igl==2.2.0 is reported to fix the issue. Keep the code unchanged, but lock the dependency version to stabilize your environment. For long-term reliability, review libigl’s release notes and pin the required version in your project configuration so that future setups reproduce the same behavior without surprises.
The article is based on a question from StackOverflow by albusdemens and an answer by Kirill Ilichev.