java-native-access/jna · warning
JNA: could not detach thread after callback handling
Error message
JNA: could not detach thread after callback handling
What it means
After a native thread finished invoking a Java callback, JNA detaches that thread from the JVM if it attached it for the duration of the call. This message is printed to stderr when DetachCurrentThread returns non-zero, meaning the thread could not be detached and stays registered with the VM — a potential thread/JNI resource leak, though the callback itself already ran.
Source
Thrown at native/dispatch.c:2092
}
else {
obj = (*env)->NewLocalRef(env, cb->object);
if ((*env)->IsSameObject(env, obj, NULL)) {
fprintf(stderr, "JNA: callback object has been garbage collected\n");
if (cif->rtype->type != FFI_TYPE_VOID)
memset(resp, 0, cif->rtype->size);
}
else {
(*env)->CallVoidMethod(env, obj, MID_ffi_callback_invoke,
A2L(cif), A2L(resp), A2L(argp));
}
(*env)->PopLocalFrame(env, NULL);
}
if (!attached) {
if ((*jvm)->DetachCurrentThread(jvm) != 0) {
fprintf(stderr, "JNA: could not detach thread after callback handling\n");
}
}
}
////////////////////
// API Methods
////////////////////
/*
* Class: com_sun_jna_Native
* Method: invokePointer
* Signature: (Lcom/sun/jna/Function;JI[Ljava/lang/Object;)J
*/
JNIEXPORT jlong JNICALL
Java_com_sun_jna_Native_invokePointer (JNIEnv *env, jclass UNUSED(cls),
jobject UNUSED(function), jlong fp,
jint callconv, jobjectArray arr)
{View on GitHub (pinned to d036ad9781)
Solutions
- Avoid foreign-thread callbacks: have native code post events to a queue drained by a Java thread, so no attach/detach happens per callback.
- Audit the callback for anything that leaves JNI references or monitors held on the thread (reentrancy, native mutexes acquired around the Java call).
- Ensure native threads are quiesced before JVM shutdown so detach is attempted on a live VM.
- Monitor thread counts to verify whether failed detaches are leaking, and restart or restructure if accumulation is observed.
Example fix
// before: native lib calls Java callback directly on C thread
native_set_event_handler(cb); // each event: attach + detach
// after: native fills a queue; Java thread drains it
native_start_queue_drain();
new Thread(() -> { while (running) handleEvent(native_pop_event()); }).start(); Defensive patterns
Strategy: fallback
Prevention
- Design native integrations so callbacks execute on Java-owned threads.
- Avoid reentrant native mutexes held across Java callback invocations.
- Track thread counts to detect leaks from repeated failed detaches.
When it happens
Trigger: A callback fired on a foreign native thread; JNA attached it, invoked the Java method, popped the local frame, and then DetachCurrentThread failed (other JNI references/monitors still held on the thread, or JVM is shutting down).
Common situations: Native libraries (media codecs, device SDKs, event loops) that invoke callbacks from their own pooled threads; JVM teardown racing with in-flight callbacks; reentrant callbacks that leave state on the thread.
Related errors
- JNA: could not detach thread after callback init
- JNA: Can't attach native thread to VM for closure handler
- JNA: could not detach thread on initial load
- JNA: Out of memory: Can't allocate local frame
- JNA: callback object has been garbage collected
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/4ff23ed8b1f0ea02.
Report an issue: GitHub.