graalpy-maven-plugin`'s own bootstrap classpath omits the Truffle NFI language, so anything needing `_ctypes` fails
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 okBoth 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.
Source: oracle/graal