{"record":{"id":"f73122d07af088ef","repo":"apache/hadoop","slug":"tlscallback-tlsfree-failed-with-error-d","errorCode":null,"errorMessage":"tlsCallback: TlsFree failed with error %d\n","messagePattern":"tlsCallback: TlsFree failed with error (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/os/windows/thread_local_storage.c","lineNumber":159,"sourceCode":" * Windows application attempts to use it via explicit linking.\n *\n * @param h module handle\n * @param reason the reason for calling the callback\n * @param pv reserved, unused\n */\nstatic void NTAPI tlsCallback(PVOID h, DWORD reason, PVOID pv)\n{\n  DWORD tlsIndex;\n  switch (reason) {\n  case DLL_THREAD_DETACH:\n    detachCurrentThreadFromJvm();\n    break;\n  case DLL_PROCESS_DETACH:\n    detachCurrentThreadFromJvm();\n    tlsIndex = gTlsIndex;\n    gTlsIndex = TLS_OUT_OF_INDEXES;\n    if (!TlsFree(tlsIndex)) {\n      fprintf(stderr, \"tlsCallback: TlsFree failed with error %d\\n\",\n        GetLastError());\n    }\n    break;\n  default:\n    break;\n  }\n}\n\n/*\n * A variable named _tls_used contains the TLS directory, which contains a list\n * of pointers to callback functions.  Normally, the linker won't retain this\n * variable unless the executable has implicit thread-local variables, defined\n * using the __declspec(thread) extended storage-class modifier.  libhdfs\n * doesn't use __declspec(thread), and we have no guarantee that the executable\n * linked to libhdfs will use __declspec(thread).  By forcing the linker to\n * reference _tls_used, we guarantee that the binary retains the TLS directory.\n * See Microsoft Visual Studio 10.0/VC/crt/src/tlssup.c .\n */","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/os/windows/thread_local_storage.c#L141-L177","documentation":"At DLL_PROCESS_DETACH the TLS callback frees the process-wide TLS index with TlsFree; the call failed and GetLastError is printed. This happens only during unload/exit; consequences are negligible because the OS reclaims TLS slots at process death, but it can indicate the index was already freed (double unload) or teardown under memory pressure.","triggerScenarios":"DLL unload where gTlsIndex was already freed or set to TLS_OUT_OF_INDEXES by a prior detach; FreeLibrary followed by exit-time callbacks; loader races during process termination.","commonSituations":"Explicit FreeLibrary of libhdfs before process exit; DLL unload ordering issues in plugin hosts.","solutions":["Ignore when it occurs during natural process exit","Do not dlopen/dlclose libhdfs repeatedly — its TLS index and JVM state are process-wide and not designed for reload cycles","Check loader logs for double-unload of the DLL"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not dlopen/dlclose libhdfs in cycles; keep it loaded for the process lifetime","Avoid explicit FreeLibrary before exit","Ignore this line when it occurs during normal process termination"],"tags":["libhdfs","windows","tls","tlsfree","dll-unload"],"backgroundTag":"tls-cleanup-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}