{"record":{"id":"64a22b74e83b071a","repo":"java-native-access/jna","slug":"jna-could-not-detach-native-thread-automatic","errorCode":null,"errorMessage":"JNA: could not detach native thread (automatic)\n","messagePattern":"JNA: could not detach native thread \\(automatic\\)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"native/callback.c","lineNumber":604,"sourceCode":"      else if (!TLS_SET(tls_thread_data_key, tls)) {\n        free(tls);\n        throwByName(env, EOutOfMemory, \"JNA: Internal TLS error\");\n        tls = NULL;\n      }\n    }\n  }\n  return tls;\n}\n\nstatic void dispose_thread_data(void* data) {\n  thread_storage* tls = (thread_storage*)data;\n  JavaVM* jvm = tls->jvm;\n  JNIEnv* env;\n  int is_attached = (*jvm)->GetEnv(jvm, (void*)&env, JNI_VERSION_1_4) == JNI_OK;\n  jboolean detached = JNI_TRUE;\n  if (is_attached) {\n    if ((*jvm)->DetachCurrentThread(jvm) != 0) {\n      fprintf(stderr, \"JNA: could not detach native thread (automatic)\\n\");\n      detached = JNI_FALSE;\n    }\n  }\n  if (tls->termination_flag && detached) {\n    *(tls->termination_flag) = JNI_TRUE;\n  }\n  free(data);\n}\n\n#ifdef _WIN32\n\nBOOL WINAPI DllMain(HINSTANCE hDLL, DWORD fdwReason, LPVOID lpvReserved) {\n  switch (fdwReason) {\n  case DLL_PROCESS_ATTACH:\n    tls_thread_data_key = TlsAlloc();\n    if (tls_thread_data_key == TLS_OUT_OF_INDEXES) {\n      return FALSE;\n    }","sourceCodeStart":586,"sourceCodeEnd":622,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/native/callback.c#L586-L622","documentation":"dispose_thread_data runs during native thread teardown (DllMain on Windows) and tries to detach a thread that JNA automatically attached to the JVM. If DetachCurrentThread returns nonzero, this warning is printed and the thread's termination flag is not set, potentially leaking the thread's TLS entry and leaving the thread attached at process exit.","triggerScenarios":"A native thread that JNA auto-attached (via dispatch_callback or thread initialization) exits while DetachCurrentThread fails — typically during DLL_PROCESS_DETACH when the JVM no longer permits attachment operations.","commonSituations":"Windows process shutdown with callbacks still registered, native threads created by third-party DLLs invoking Java callbacks, JVM already destroyed/unloading before the native thread detaches.","solutions":["Explicitly dispose callbacks (CallbackReference disposal / dropping all Callback references) and ensure native threads finish before JVM shutdown.","Avoid invoking Java callbacks from native threads that outlive the JVM (e.g. during DllMain/process exit).","Unregister threads via JNA's native thread cleanup APIs instead of relying on automatic detach at exit.","Treat as benign if it only appears at process exit; otherwise investigate JVM/native library unload ordering."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Release all Callback references before JVM shutdown so auto-attached threads are cleaned deterministically","Do not fire Java callbacks from native threads during process/DLL teardown","Explicitly terminate native worker threads before System.exit","Treat at-exit occurrences of this message as benign; act on mid-run occurrences"],"tags":["jni","threading","detach","shutdown"],"backgroundTag":"thread-detach-failed","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}