java-native-access/jna · warning
JNA: could not detach thread
Error message
JNA: could not detach thread
What it means
At the end of dispatch_callback, if the thread was attached solely for this callback and the callback did not request staying attached (needs_detach), JNA calls DetachCurrentThread. A nonzero result prints this warning; the thread remains attached to the JVM, leaking the attachment until the thread exits.
Source
Thrown at native/callback.c:756
fprintf(stderr, "JNA: couldn't obtain thread-local storage\n");
return;
}
// Give the callback glue its own local frame to ensure all local references
// are properly disposed
if ((*env)->PushLocalFrame(env, 16) < 0) {
fprintf(stderr, "JNA: Out of memory: Can't allocate local frame\n");
}
else {
invoke_callback(env, cb, cif, resp, cbargs);
// Make note of whether the callback wants to avoid detach
needs_detach = tls->needs_detach && !tls->jvm_thread;
(*env)->PopLocalFrame(env, NULL);
}
if (needs_detach) {
if ((*jvm)->DetachCurrentThread(jvm) != 0) {
fprintf(stderr, "JNA: could not detach thread\n");
}
}
}
const char*
JNA_callback_init(JNIEnv* env) {
#ifdef PTHREADS
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
pthread_once(&key_once, make_thread_data_key);
#endif
if (!LOAD_CREF(env, Object, "java/lang/Object")) return "java.lang.Object";
return NULL;
}
void
JNA_callback_dispose(JNIEnv* env) {View on GitHub (pinned to d036ad9781)
Solutions
- Ensure no outstanding JNI local/global references pin the thread when detaching (PopLocalFrame ran, callback fully returned).
- Keep the thread attached intentionally (long-lived native worker) instead of attach/detach per callback.
- Check for reentrancy: don't detach from within a nested callback on the same thread.
- Update JNA; detach ordering was fixed in several versions.
Defensive patterns
Strategy: fallback
Prevention
- Keep long-lived native workers attached instead of attach/detach per callback
- Ensure callbacks fully return (no retained local frames) before detach
- Avoid nested callbacks that reenter dispatch on the same thread
- Keep JNA current; detach ordering fixes exist in newer releases
When it happens
Trigger: DetachCurrentThread fails for a native thread that invoked a callback — typically because native frames or TLS state still reference the JVM, or detach is attempted from a context where the JVM disallows it (shutdown, still running attached code).
Common situations: Callbacks that spawn or retain JNI references on the native thread, detach attempted while still executing inside the callback frame, JVM teardown racing a late callback, non-Java threads firing callbacks asynchronously.
Related errors
- JNA: could not detach native thread (automatic)
- JNA: couldn't obtain thread-local storage
- JNA: Can't attach native thread to VM for callback thread in
- JNA: Unhandled result conversion: %d
- JNA: error while handling callback exception, continuing
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/64bc11da5d49ecb9.
Report an issue: GitHub.