#14339·graal

graalpy-maven-plugin`'s own bootstrap classpath omits the Truffle NFI language, so anything needing `_ctypes` fails

Author: zenbonesCreated Aug 30, 2026Updated Sep 4, 2026
Labelsbugpython

Symptom:

[INFO] Running GraalPy: ... com.oracle.graal.python.shell.GraalPythonMain C:\Users\david\AppData\Local\Temp\create_launcher....py
[ERROR] ERROR: ModuleNotFoundError: No module named '_ctypes'

Root cause — reproduced directly by invoking GraalPythonMain with the exact classpath the plugin itself logs for its internal bootstrap:

$ java ... -classpath <plugin's own logged classpath> com.oracle.graal.python.shell.GraalPythonMain -c "import _ctypes"

java.lang.IllegalStateException: No language for id nfi found. Supported languages are: [python, regex]
	at com.oracle.truffle.polyglot.PolyglotEngineImpl.findLanguage(PolyglotEngineImpl.java:952)
	at com.oracle.graal.python.builtins.modules.ctypes.CtypesModuleBuiltins$DlOpenNode.load(CtypesModuleBuiltins.java:673)
	at com.oracle.graal.python.builtins.modules.ctypes.CtypesModuleBuiltins.postInitialize(CtypesModuleBuiltins.java:270)
	...

GraalPy's _ctypes module is implemented on top of Truffle's NFI (Native Function Interface) language. The classpath graalpy-maven-plugin constructs for its own internal GraalPythonMain invocations only registers the python and regex Truffle languages — nfi is never on it. Any code path needing _ctypes (explicit import ctypes/_ctypes, comtypes, and apparently some GraalPy versions' own site initialization) fails with this IllegalStateException, which GraalPythonMain surfaces to the user as the more confusing ModuleNotFoundError: No module named '_ctypes'.

Fix, confirming the diagnosis — adding both missing artifacts to the classpath resolves it:

$ java ... -classpath <same classpath>;truffle-nfi-25.0.2.jar com.oracle.graal.python.shell.GraalPythonMain -c "import _ctypes"
polyglot.ForeignException: Unknown NFI backend 'native'.

$ java ... -classpath <same classpath>;truffle-nfi-25.0.2.jar;truffle-nfi-libffi-25.0.2.jar com.oracle.graal.python.shell.GraalPythonMain -c "import _ctypes; print('ctypes ok')"
ctypes ok

Both org.graalvm.truffle:truffle-nfi (the NFI language) and org.graalvm.truffle:truffle-nfi-libffi (the native NFI backend implementation) are required — truffle-nfi alone finds the language but has no backend for it. Both artifacts are published and versioned in lock-step with everything else on that classpath (org.graalvm.truffle:truffle-nfi-libffi:<graalvm.version>), so this looks like a straightforward missing dependency in graalpy-maven-plugin's own POM/classpath construction for its bootstrap invocations. It is not fixable from a consuming project's pom.xml: the plugin forks a separate java process with a classpath it resolves internally (via its own bundled dependency downloader), not the Mojo's own plugin-dependency classpath.