{"record":{"id":"7dcb5da0ad9e747f","repo":"apache/hadoop","slug":"call-to-attachcurrentthread-failed-with-error-d","errorCode":null,"errorMessage":"Call to AttachCurrentThread failed with error: %d\n","messagePattern":"Call to AttachCurrentThread failed with error: (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/jni_helper.c","lineNumber":763,"sourceCode":"                    \"with error: %d\\n\", rv);\n            return NULL;\n        }\n\n        // We use findClassAndInvokeMethod here because the jclasses in\n        // jclasses.h have not loaded yet\n        jthr = findClassAndInvokeMethod(env, NULL, STATIC, NULL, HADOOP_FS,\n                \"loadFileSystems\", \"()V\");\n        if (jthr) {\n            printExceptionAndFree(env, jthr, PRINT_EXC_ALL,\n                    \"FileSystem: loadFileSystems failed\");\n            return NULL;\n        }\n    } else {\n        //Attach this thread to the VM\n        vm = vmBuf[0];\n        rv = (*vm)->AttachCurrentThread(vm, (void*)&env, 0);\n        if (rv != 0) {\n            fprintf(stderr, \"Call to AttachCurrentThread \"\n                    \"failed with error: %d\\n\", rv);\n            return NULL;\n        }\n    }\n\n    return env;\n}\n\n/**\n * getJNIEnv: A helper function to get the JNIEnv* for the given thread.\n * If no JVM exists, then one will be created. JVM command line arguments\n * are obtained from the LIBHDFS_OPTS environment variable.\n *\n * Implementation note: we rely on POSIX thread-local storage (tls).\n * This allows us to associate a destructor function with each thread, that\n * will detach the thread from the Java VM when the thread terminates.  If we\n * failt to do this, it will cause a memory leak.\n *","sourceCodeStart":745,"sourceCodeEnd":781,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/jni_helper.c#L745-L781","documentation":"A thread calling into libhdfs found an already-created JVM (JNI_GetCreatedJavaVMs returned one, so this is the second or later thread) and AttachCurrentThread failed with a non-zero JNI code (typically JNI_EVERSION or native-resource failure). getGlobalJNIEnv returns NULL, so this thread's HDFS call fails while other, already-attached threads keep working.","triggerScenarios":"Multi-threaded programs where a worker's first libhdfs call happens after another thread created the VM and the attach fails: JNI version negotiation problems after a JVM change, JVM unable to allocate per-thread native structures under memory pressure, or calls racing JVM destruction at shutdown.","commonSituations":"Thread pools creating threads late under heavy load; applications embedding libhdfs alongside another JVM owner; shutdown paths where a lingering thread calls an HDFS API while DestroyJavaVM is running.","solutions":["Warm up each worker thread at startup with a cheap call (hdfsExists on \"/\") so attachment happens before real work and fails visibly","For code -3 (JNI_EVERSION), align the runtime libjvm with the JVM libhdfs was built against","For other codes, reduce concurrent thread count or raise memory limits so the JVM can allocate thread structures","Make sure no thread issues HDFS calls while the process is tearing the JVM down"],"exampleFix":"// before: first libhdfs touch deep inside worker\nvoid* worker(void *arg) {\n    hdfsRead(fs, file, buf, n);  /* attach fails mid-job */\n}\n\n// after: force attach at thread start, fail fast\nvoid* worker(void *arg) {\n    if (!fs_attached_ok()) return NULL;  /* calls any hdfs API to trigger getJNIEnv */\n    hdfsRead(fs, file, buf, n);\n}","handlingStrategy":"fallback","validationCode":"/* Warm up each worker: force attach at thread start, not mid-job */\nstatic void warm_thread(hdfsFS fs) {\n    hdfsExists(fs, \"/\"); /* any call routes through getJNIEnv */\n}","typeGuard":null,"tryCatchPattern":"if (someHdfsCall(fs) == -1 && errno == EINTERNAL) {\n    /* attach failed for this thread; route work to an attached worker */\n    enqueue_to_io_thread(op); /* fallback: single dedicated I/O thread */\n}","preventionTips":["Warm up every worker thread with a cheap HDFS call before real work","Prefer one dedicated I/O thread over ad-hoc threads calling libhdfs","Stop threads before initiating JVM teardown at shutdown"],"tags":["libhdfs","jni","attachcurrentthread","multithreading","jvm"],"backgroundTag":"jni-thread-attach-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}