java-native-access/jna · error · java.lang.UnsatisfiedLinkError

Library has been unloaded

Error message

Library has been unloaded

What it means

NativeLibrary.getSymbolAddress throws UnsatisfiedLinkError when the library handle is 0, meaning the library has already been disposed via dispose() (or finalization) and its native handle released. No further symbol lookups are possible on that instance.

Source

Thrown at src/com/sun/jna/NativeLibrary.java:649

     * @param symbolName
     * @return Pointer representing the global variable address
     * @throws UnsatisfiedLinkError if the symbol is not found
     */
    public Pointer getGlobalVariableAddress(String symbolName) {
        try {
            return new Pointer(getSymbolAddress(symbolName));
        } catch(UnsatisfiedLinkError e) {
            throw new UnsatisfiedLinkError("Error looking up '" + symbolName + "': " + e.getMessage());
        }
    }

    /**
     * Used by the Function class to locate a symbol
     * @throws UnsatisfiedLinkError if the symbol can't be found
     */
    long getSymbolAddress(String name) {
        if (handle == 0) {
            throw new UnsatisfiedLinkError("Library has been unloaded");
        }
        return this.symbolProvider.getSymbolAddress(handle, name, NATIVE_SYMBOL_PROVIDER);
    }

    @Override
    public String toString() {
        return "Native Library <" + libraryPath + "@" + handle + ">";
    }
    /** Returns the simple name of this library. */
    public String getName() {
        return libraryName;
    }
    /**
     * Returns the file on disk corresponding to this NativeLibrary instance.
     * If this NativeLibrary represents the current process, this function will return null.
     */
    public File getFile() {
        if (libraryPath == null)

View on GitHub (pinned to d036ad9781)

Solutions

  1. Do not dispose the NativeLibrary while Functions derived from it are still in use
  2. Re-acquire the library with NativeLibrary.getInstance(name) after disposal
  3. Reorder shutdown logic so library disposal is the last step
  4. Check for accidental dispose() calls (e.g. in finally blocks or finalizers)

Example fix

// before
lib.dispose();
Function f = lib.getFunction("foo"); // throws
// after
Function f = lib.getFunction("foo");
f.invoke(...);
lib.dispose(); // dispose last
Defensive patterns

Strategy: validation

Validate before calling

if (lib != null && isDisposed(lib)) {
    lib = NativeLibrary.getInstance("mylib");
}

Try / catch

try {
    Function f = lib.getFunction("foo");
} catch (UnsatisfiedLinkError e) {
    if (e.getMessage().contains("unloaded")) {
        lib = NativeLibrary.getInstance("mylib"); // reacquire
    }
}

Prevention

When it happens

Trigger: Calling lib.getFunction(...), lib.getGlobalVariableAddress(...), or invoking a previously obtained Function after calling lib.dispose(); holding a Function object past the library's cleanup.

Common situations: Explicit NativeLibrary.dispose() in shutdown code followed by late callbacks or pending invocations; garbage collection finalizing the library while a Function is still referenced; reusing a cached library object after unload.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/7ee9560a6a451894. Report an issue: GitHub.