{"record":{"id":"aaff7b36c50a145d","repo":"apache/hadoop","slug":"getjnienv-unable-to-create-threadlocalstate","errorCode":null,"errorMessage":"getJNIEnv: Unable to create ThreadLocalState\n","messagePattern":"getJNIEnv: Unable to create ThreadLocalState\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/jni_helper.c","lineNumber":818,"sourceCode":"      return NULL;\n    }\n    if (state) {\n      mutexUnlock(&jvmMutex);\n\n      // Free any stale exception strings.\n      free(state->lastExceptionRootCause);\n      free(state->lastExceptionStackTrace);\n      state->lastExceptionRootCause = NULL;\n      state->lastExceptionStackTrace = NULL;\n\n      return state->env;\n    }\n\n    /* Create a ThreadLocalState for this thread */\n    state = threadLocalStorageCreate();\n    if (!state) {\n      mutexUnlock(&jvmMutex);\n      fprintf(stderr, \"getJNIEnv: Unable to create ThreadLocalState\\n\");\n      return NULL;\n    }\n\n    state->env = getGlobalJNIEnv();\n    if (!state->env) {\n        mutexUnlock(&jvmMutex);\n        goto fail;\n    }\n\n    jthrowable jthr = NULL;\n    jthr = initCachedClasses(state->env);\n    if (jthr) {\n      mutexUnlock(&jvmMutex);\n      printExceptionAndFree(state->env, jthr, PRINT_EXC_ALL,\n                            \"initCachedClasses failed\");\n      goto fail;\n    }\n","sourceCodeStart":800,"sourceCodeEnd":836,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/jni_helper.c#L800-L836","documentation":"getJNIEnv() could not allocate the per-thread ThreadLocalState: threadLocalStorageCreate() returned NULL because malloc failed (the companion message 'threadLocalStorageCreate: OOM ...' prints just before). This is C-heap exhaustion at the moment of first per-thread initialization; getJNIEnv releases the global lock and returns NULL, failing the current HDFS call.","triggerScenarios":"First libhdfs call on a thread when malloc of sizeof(struct ThreadLocalState) fails: cgroup memory cap reached, RLIMIT_AS/RLIMIT_DATA hit, or a severe native leak.","commonSituations":"Long-running daemons that slowly leak until the container OOM boundary; stress tests under valgrind overhead; containers with tight MemoryMax.","solutions":["Treat as OOM: compare process RSS against cgroup MemoryMax / ulimit -v and raise the limit or restart the leaked process","Run under valgrind or ASan to find the native leak if it recurs","Retry once memory pressure passes; the allocation is small and transient"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"hdfsFS fs = hdfsConnectAsUser(nn, port, user);\nif (!fs && errno == ENOMEM) {\n    sleep(1);              /* let memory pressure pass */\n    fs = hdfsConnectAsUser(nn, port, user);\n}\nif (!fs) return EXIT_FAILURE;","preventionTips":["Cap concurrent worker threads so per-thread allocations stay bounded","Monitor RSS against container MemoryMax and alert before the OOM boundary","Retry ENOMEM once, then fail loudly instead of looping"],"tags":["libhdfs","out-of-memory","malloc","thread-local-storage"],"backgroundTag":"out-of-memory","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}