Skip to content

Fix jansi native library errors on Windows GraalVM native image#34

Open
Copilot wants to merge 4 commits intomainfrom
copilot/fix-could-not-load-library-error
Open

Fix jansi native library errors on Windows GraalVM native image#34
Copilot wants to merge 4 commits intomainfrom
copilot/fix-could-not-load-library-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 4, 2026

On Windows, running kubectl-kport.exe init crashes because jline-2.14.6.jar is a fat/shaded JAR that bundles jansi 1.12 and hawtjni-runtime inside it. The jline-bundled org.fusesource.jansi.AnsiConsole (jansi 1.x) class is used at runtime due to classpath resolution order, and its CLibrary.<clinit> uses hawtjni's Library.doLoad() to load the native library.

Root cause

Two issues prevent the native library from initializing correctly in the GraalVM native binary:

  1. Missing DLL resources: hawtjni looks for the Windows DLL at META-INF/native/windows64/jansi.dll via ClassLoader.getResource(), but this resource from jline-2.14.6.jar is not embedded in the GraalVM native binary by default.

  2. Missing JNI field registrations: Once the DLL loads, its native init() method calls back via JNI (GetStaticFieldID) to set ~61 static fields on CLibrary, Kernel32, and their inner classes. GraalVM's JNI layer throws NoSuchFieldError (e.g. CLibrary.STDIN_FILENO) because those fields are not registered for JNI access.

Fix

1. Embed the hawtjni-format Windows DLL resources

Add the DLL resource paths to quarkus.native.resources.includes in both modules:

quarkus.native.resources.includes=...,META-INF/native/windows64/jansi.dll,META-INF/native/windows32/jansi.dll

2. Register jansi 1.x internal classes for JNI access

Add a jni-config.json to both modules registering all org.fusesource.jansi.internal.* classes (CLibrary, CLibrary$Termios, CLibrary$WinSize, Kernel32, and all Kernel32 inner classes) with allDeclaredFields, allDeclaredMethods, and allDeclaredConstructors. Wire it up via:

quarkus.native.additional-build-args=...,-H:JNIConfigurationFiles=jni-config.json,...

Both kubectl-kport and kport-ide-server application.properties and resources are updated. Including the Windows DLL resources in non-Windows builds is harmless — hawtjni will simply never load the wrong-platform DLL.

…lVM native image

Explicitly add jansi Windows DLL resources to quarkus.native.resources.includes
in both kubectl-kport and kport-ide-server application.properties.

When running the GraalVM native binary on Windows, CLibrary.<clinit> triggers
hawtjni's JansiLoader which tries to extract the embedded jansi.dll from
classpath resources. The DLL was missing from the native image binary because
the jansi JAR's META-INF/native-image/resource-config.json pattern is not
being applied on Windows GraalVM 24 native image builds. By explicitly
including the DLL resource paths in quarkus.native.resources.includes, the
native image will always embed the Windows DLLs so they can be extracted and
loaded at runtime.

Agent-Logs-Url: https://github.com/eclipse-jkube/kport/sessions/cc908d9a-d730-4224-b6f2-cbdc3d4fde32

Co-authored-by: sunix <[email protected]>
Copilot AI changed the title [WIP] Fix could not load library error on Windows PowerShell running kubectl kport init Fix jansi native library UnsatisfiedLinkError on Windows GraalVM native image Apr 4, 2026
Copilot finished work on behalf of sunix April 4, 2026 20:23
Copilot AI requested a review from sunix April 4, 2026 20:23
@sunix
Copy link
Copy Markdown
Member

sunix commented Apr 4, 2026

/build-native-windows

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 4, 2026

🏁 Native build results

Windows: success

➡️ Download artifacts from this Actions run

Artifacts expire after 1 day.

@sunix
Copy link
Copy Markdown
Member

sunix commented Apr 4, 2026

@copilot not better

PS C:\Users\crew\Downloads\kubectl-kport-Windows> .\kubectl-kport.exe init
[?k8s-kport] Failed to start application: java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [Can't load library: jansi | java.library.path = [C:\Users\crew\Downloads\kubectl-kport-Windows, C:\WINDOWS\system32, C:\WINDOWS, C:\Windows\System32, C:\Windows, C:\Windows\System32\wbem, C:\Windows\System32\WindowsPowerShell\v1.0\, C:\Windows\System32\OpenSSH\, C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common, C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR, C:\Windows\System32, C:\Windows, C:\Windows\System32\wbem, C:\Windows\System32\WindowsPowerShell\v1.0\, C:\Windows\System32\OpenSSH\, C:\Program Files (x86)\GnuPG\bin, C:\Program Files\Git\cmd, C:\Program Files\RedHat\Podman\, C:\Users\crew\AppData\Local\Microsoft\WindowsApps, C:\Users\crew\AppData\Local\Programs\Microsoft VS Code\bin, C:\Users\crew\graalvm\graalvm-jdk-22\bin, C:\Users\crew\.sdkman\candidates\maven\current\bin, C:\Users\crew\AppData\Local\Programs\Ollama, C:\Program Files\JetBrains\IntelliJ IDEA 2024.1.4\bin, ., C:\Users\crew\AppData\Local\Microsoft\WinGet\Packages\Schniz.fnm_Microsoft.Winget.Source_8wekyb3d8bbwe, C:\Users\crew\AppData\Local\fnm_multishells\25304_1725258627897, ., .]]
        at org.fusesource.hawtjni.runtime.Library.doLoad(Library.java:182)
        at org.fusesource.hawtjni.runtime.Library.load(Library.java:140)
        at org.fusesource.jansi.internal.CLibrary.<clinit>(CLibrary.java:42)
        at org.fusesource.jansi.AnsiConsole.wrapOutputStream(AnsiConsole.java:48)
        at org.fusesource.jansi.AnsiConsole.<clinit>(AnsiConsole.java:38)
        at picocli.CommandLine$Help$Ansi.calcIsJansiConsoleInstalled(CommandLine.java:17977)
        at picocli.CommandLine$Help$Ansi.isJansiConsoleInstalled(CommandLine.java:17954)
        at picocli.CommandLine$Help$Ansi.ansiPossible(CommandLine.java:17942)
        at picocli.CommandLine$Help$Ansi.enabled(CommandLine.java:17998)
        at picocli.CommandLine$Help$Ansi$Text.toString(CommandLine.java:18368)
        at org.eclipse.jkube.kport.commands.InitCommand.text(InitCommand.java:147)
        at org.eclipse.jkube.kport.commands.InitCommand.printText(InitCommand.java:143)
        at org.eclipse.jkube.kport.commands.InitCommand.run(InitCommand.java:87)
        at picocli.CommandLine.executeUserObject(CommandLine.java:2045)
        at picocli.CommandLine.access$1500(CommandLine.java:148)
        at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2469)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2461)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2423)
        at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2277)
        at picocli.CommandLine$RunLast.execute(CommandLine.java:2425)
        at io.quarkus.picocli.runtime.PicocliRunner$EventExecutionStrategy.execute(PicocliRunner.java:26)
        at picocli.CommandLine.execute(CommandLine.java:2174)
        at io.quarkus.picocli.runtime.PicocliRunner.run(PicocliRunner.java:40)
        at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:149)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:79)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:50)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)
        at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

PS C:\Users\crew\Downloads\kubectl-kport-Windows>

…esources from jline

jline-2.14.6.jar bundles jansi 1.12 with hawtjni-runtime classes shaded inside
it. The jline-bundled AnsiConsole (jansi 1.x) is resolved at runtime and uses
hawtjni's Library.doLoad() which looks for DLLs at META-INF/native/windows64/
(hawtjni resource format), NOT at org/fusesource/jansi/internal/native/Windows/
(JansiLoader format from standalone jansi 2.x).

Previous fix: embedded the wrong (JansiLoader) resource paths
This fix: embed the correct (hawtjni) resource paths from jline's bundled jansi

Agent-Logs-Url: https://github.com/eclipse-jkube/kport/sessions/494c0309-030f-48a9-8590-673c5bd8b2d7

Co-authored-by: sunix <[email protected]>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 4, 2026

@copilot not better

...

The previous fix was incorrect - it was embedding the wrong resource paths.

Root cause: jline-2.14.6.jar is a fat JAR that shades jansi 1.12 and hawtjni-runtime inside it, with Windows DLLs at META-INF/native/windows64/jansi.dll. The jline-bundled AnsiConsole (jansi 1.x) class is what gets used at runtime, and its CLibrary.<clinit> calls hawtjni's Library.doLoad() which looks for the DLL at META-INF/native/windows64/jansi.dll - NOT at org/fusesource/jansi/internal/native/Windows/x86_64/jansi.dll (the JansiLoader path I was incorrectly embedding before).

Fixed in dd90461 by changing quarkus.native.resources.includes to embed META-INF/native/windows64/jansi.dll and META-INF/native/windows32/jansi.dll - the exact paths hawtjni's Library.doLoad() looks for via ClassLoader.getResource().

Copilot finished work on behalf of sunix April 4, 2026 21:15
@sunix
Copy link
Copy Markdown
Member

sunix commented Apr 4, 2026

/build-native-windows

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 4, 2026

🏁 Native build results

Windows: success

➡️ Download artifacts from this Actions run

Artifacts expire after 1 day.

@sunix
Copy link
Copy Markdown
Member

sunix commented Apr 5, 2026

@copilot interesting, I have something different now

PS C:\Users\crew\Downloads\kubectl-kport-Windows.exe> .\kubectl-kport.exe init
[?k8s-kport] Failed to start application: java.lang.NoSuchFieldError: org.fusesource.jansi.internal.CLibrary.STDIN_FILENO
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions$Support.getFieldID(JNIFunctions.java:1869)
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.functions.JNIFunctions.GetStaticFieldID(JNIFunctions.java:467)
        at org.fusesource.jansi.internal.CLibrary.init(Native Method)
        at org.fusesource.jansi.internal.CLibrary.<clinit>(CLibrary.java:43)
        at org.fusesource.jansi.AnsiConsole.wrapOutputStream(AnsiConsole.java:48)
        at org.fusesource.jansi.AnsiConsole.<clinit>(AnsiConsole.java:38)
        at picocli.CommandLine$Help$Ansi.calcIsJansiConsoleInstalled(CommandLine.java:17977)
        at picocli.CommandLine$Help$Ansi.isJansiConsoleInstalled(CommandLine.java:17954)
        at picocli.CommandLine$Help$Ansi.ansiPossible(CommandLine.java:17942)
        at picocli.CommandLine$Help$Ansi.enabled(CommandLine.java:17998)
        at picocli.CommandLine$Help$Ansi$Text.toString(CommandLine.java:18368)
        at org.eclipse.jkube.kport.commands.InitCommand.text(InitCommand.java:147)
        at org.eclipse.jkube.kport.commands.InitCommand.printText(InitCommand.java:143)
        at org.eclipse.jkube.kport.commands.InitCommand.run(InitCommand.java:87)
        at picocli.CommandLine.executeUserObject(CommandLine.java:2045)
        at picocli.CommandLine.access$1500(CommandLine.java:148)
        at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2469)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2461)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2423)
        at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2277)
        at picocli.CommandLine$RunLast.execute(CommandLine.java:2425)
        at io.quarkus.picocli.runtime.PicocliRunner$EventExecutionStrategy.execute(PicocliRunner.java:26)
        at picocli.CommandLine.execute(CommandLine.java:2174)
        at io.quarkus.picocli.runtime.PicocliRunner.run(PicocliRunner.java:40)
        at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:149)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:79)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:50)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)
        at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

PS C:\Users\crew\Downloads\kubectl-kport-Windows.exe>

… on Windows

The jansi 1.x DLL (from jline-2.14.6 fat JAR) loads successfully via
META-INF/native/windows64/jansi.dll, but its native init() method calls back
via JNI (GetStaticFieldID) to set static fields on CLibrary, Kernel32 and their
inner classes. GraalVM's JNI layer throws NoSuchFieldError for STDIN_FILENO
because those fields are not registered for JNI access.

Add jni-config.json to both kubectl-kport and kport-ide-server registering all
jansi 1.x internal classes with allDeclaredFields, allDeclaredMethods, and
allDeclaredConstructors. Wire up via -H:JNIConfigurationFiles=jni-config.json.

Agent-Logs-Url: https://github.com/eclipse-jkube/kport/sessions/4a2c5570-5de8-447e-9f75-041f4665c925

Co-authored-by: sunix <[email protected]>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 5, 2026

@copilot interesting, I have something different now

PS C:\Users\crew\Downloads\kubectl-kport-Windows.exe> .\kubectl-kport.exe init

...

Progress! The DLL now loads (resource path fix worked), but the jansi 1.x DLL's init() native method calls back via JNI to set static fields on CLibrary (like STDIN_FILENO), and GraalVM throws NoSuchFieldError because those fields aren't registered for JNI access.

Fixed in 55e05d4 by adding jni-config.json to both modules that registers all jansi 1.x internal classes (CLibrary, Kernel32, and all their inner classes) with allDeclaredFields: true. Wired up via -H:JNIConfigurationFiles=jni-config.json in both application.properties.

Copilot AI changed the title Fix jansi native library UnsatisfiedLinkError on Windows GraalVM native image Fix jansi native library errors on Windows GraalVM native image Apr 5, 2026
Copilot finished work on behalf of sunix April 5, 2026 07:52
@sunix
Copy link
Copy Markdown
Member

sunix commented Apr 5, 2026

/build-native-windows

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 5, 2026

🏁 Native build results

Windows: success

➡️ Download artifacts from this Actions run

Artifacts expire after 1 day.

@sunix sunix marked this pull request as ready for review April 5, 2026 09:42
@sunix
Copy link
Copy Markdown
Member

sunix commented Apr 5, 2026

/build-native-linux

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 5, 2026

🏁 Native build results

Linux: success

➡️ Download artifacts from this Actions run

Artifacts expire after 1 day.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Could not load library. error on Windows powershell running kubectl kport init

2 participants