Troubleshooting

May 15, 2026 ยท View on GitHub

Common errors and solutions when using godot-java.

For projects created from godot-java-template, start with:

./mvnw package
./mvnw verify -Pgodot-doctor

package builds and syncs Java and native artifacts. godot-doctor checks the JDK version, Godot project files, godot/godot-java/app.jar, and the platform native library. It also verifies that the generated Java class registry is present inside app.jar.


1. JVM Not Found

Symptom:

ERROR: JVM not found at path: /path/to/jvm

Cause: JAVA_HOME is unset, points to the wrong JDK, or JDK 25+ is not installed.

Solution:

Verify Java installation:

java -version          # must show 25+
/usr/libexec/java_home -V   # macOS: list installed JDKs

Set JAVA_HOME:

# macOS/Linux
export JAVA_HOME=$(/usr/libexec/java_home -v 25)   # macOS
export JAVA_HOME=/usr/lib/jvm/java-25              # Linux

# Windows (PowerShell)
[System.Environment]::SetEnvironmentVariable("JAVA_HOME", "C:\Path\To\JDK-25", "User")

2. Native Library Load Failure

Symptom:

ERROR: Can't open dynamic library: godot-java/libgodot-java.so

Cause: Missing library, wrong path in .gdextension, or architecture mismatch.

Solution:

  1. Verify the library file exists:
ls -lh godot-java/libgodot-java.dylib    # macOS
file godot-java/libgodot-java.dylib       # check architecture
  1. Check .gdextension configuration:
[configuration]
entry_symbol = "godot_java_init"
compatibility_minimum = 4.6

[libraries]
macos.debug = "res://godot-java/libgodot-java.dylib"
macos.release = "res://godot-java/libgodot-java.dylib"
linux.debug = "res://godot-java/libgodot-java.so"
linux.release = "res://godot-java/libgodot-java.so"
windows.debug = "res://godot-java/libgodot-java.dll"
windows.release = "res://godot-java/libgodot-java.dll"

Common mistakes:

  • Wrong file extension (.dll vs .so vs .dylib).
  • Wrong platform key (macos not osx).
  • Incorrect path (res://godot-java/ should match the project-local runtime directory).
  • Running mvn compile instead of mvn package; the template syncs runtime files during package.

In the template, the expected runtime layout is:

godot/
  godot-java.gdextension
  godot-java/
    app.jar
    libgodot-java.dylib    # macOS
    libgodot-java.so       # Linux
    libgodot-java.dll      # Windows
  1. Check library dependencies:
otool -L godot-java/libgodot-java.dylib    # macOS
ldd godot-java/libgodot-java.so             # Linux

3. Compile Errors

3.1 Java Version Requirement

Symptom:

error: cannot find symbol java.lang.foreign.MemorySegment

Cause: JDK is older than 25.

Solution: Install JDK 25+ and verify:

java -version    # must show 25+

3.2 Package Does Not Exist

Symptom:

error: package org.godot.annotation does not exist

Cause: godot-java-core dependency is missing or not resolved.

Solution:

mvn clean compile

Verify the dependency in pom.xml:

<dependency>
    <groupId>io.github.youngledo</groupId>
    <artifactId>godot-java-core</artifactId>
    <version>LATEST_VERSION</version>
</dependency>

4. Runtime Crashes (SIGBUS / SIGSEGV)

Symptom:

Signal: SIGBUS (Bad address)
Signal: SIGSEGV (Segmentation fault)

Possible causes:

  1. Invalid native pointer -- calling methods on a freed or uninitialized object.
  2. Arena lifecycle violation -- accessing memory after an Arena is closed.
  3. Godot version mismatch -- running with Godot older than 4.6.

Solutions:

Check Godot version:

godot --version    # must be 4.6+

Always validate objects before calling:

if (!isValid()) {
    return;  // native pointer is 0
}

Check for JVM crash logs:

ls hs_err_pid*.log
cat $(ls -t hs_err_pid*.log | head -1)

5. Class Not Found

Symptom:

ERROR: Class not found: com.example.MyClass

Cause: Class is not compiled, not on the classpath, or not annotated.

Solution:

  1. For template projects, rebuild and sync the fat jar:
./mvnw package
  1. Verify the class is compiled:
find target/classes -name "MyClass.class"
  1. Verify the synced jar exists:
ls -lh godot/godot-java/app.jar
  1. Verify the class has the @GodotClass annotation:
@GodotClass(name = "MyClass", parent = "Node")
public class MyClass extends Node { }
  1. Restart Godot after rebuilding if the editor was already open. The JVM and registered Java classes are initialized when the extension loads, so changed Java classes are not guaranteed to appear in an existing editor session.

6. Method Not Callable from GDScript

Symptom:

ERROR: Method 'my_method' not found

Cause: Missing @GodotMethod annotation, or method is private.

Solution:

// Wrong: no annotation
public void myMethod() { }

// Wrong: private method
@GodotMethod
private void myMethod() { }

// Correct
@GodotMethod
public void myMethod() { }

Also check:

  • Parameter types are supported (int, long, float, double, boolean, String, GodotObject).
  • The method is on a class that has @GodotClass.

7. @Export Property Not Visible in Editor

Symptom: Property does not appear in the Godot Inspector panel.

Cause: Field type is not supported, or field is static/final.

Solution:

Supported types: int, long, float, double, boolean, String, GodotArray, GodotDictionary.

// Wrong
@Export
private static int count = 0;

@Export
private final String name = "fixed";

// Correct
@Export
private int count = 0;

@Export
private String name = "editable";

8. Godot Version Mismatch

Symptom:

ERROR: GDExtension version mismatch

Solution:

Verify Godot version:

godot --version    # must be 4.6+

Update .gdextension:

[configuration]
compatibility_minimum = 4.6

9. Performance Issues

Symptom: Low frame rate, stuttering.

Cause: Excessive cross-boundary calls, per-frame allocations, or verbose logging.

Solutions:

  1. Cache frequently accessed values:
private String cachedName;

@Override
public void _ready() {
    cachedName = getName();    // one native call
}

@Override
public void _process(double delta) {
    // Use cachedName instead of calling getName() every frame
}
  1. Throttle logging:
private int frameCount = 0;

@Override
public void _process(double delta) {
    if (frameCount % 60 == 0) {
        System.out.println("Position: " + getX() + ", " + getY());
    }
    frameCount++;
}
  1. Minimize cross-boundary calls. Each call() from Java to Godot costs ~300-600ns (Panama + method bind lookup + variant conversion).

Getting Help

If none of the above resolves your issue:

  1. Enable debug logging in the C++ layer: #define GODOT_JAVA_DEBUG 1
  2. Create a minimal reproduction case.
  3. File a GitHub Issue with:
    • Godot version (godot --version)
    • Java version (java -version)
    • OS and architecture
    • Full error output
    • Minimal code sample