{"record":{"id":"93a51501848226f3","repo":"apache/hadoop","slug":"mutexlock-pthread-mutex-lock-failed-with-error-d","errorCode":null,"errorMessage":"mutexLock: pthread_mutex_lock failed with error %d\n","messagePattern":"mutexLock: pthread_mutex_lock failed with error (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/os/posix/mutexes.c","lineNumber":37,"sourceCode":"#include \"os/mutexes.h\"\n\n#include <pthread.h>\n#include <stdio.h>\n\nmutex jvmMutex;\nmutex jclassInitMutex = PTHREAD_MUTEX_INITIALIZER;\npthread_mutexattr_t jvmMutexAttr;\n\n__attribute__((constructor)) static void init() {\n  pthread_mutexattr_init(&jvmMutexAttr);\n  pthread_mutexattr_settype(&jvmMutexAttr, PTHREAD_MUTEX_RECURSIVE);\n  pthread_mutex_init(&jvmMutex, &jvmMutexAttr);\n}\n\nint mutexLock(mutex *m) {\n  int ret = pthread_mutex_lock(m);\n  if (ret) {\n    fprintf(stderr, \"mutexLock: pthread_mutex_lock failed with error %d\\n\",\n      ret);\n  }\n  return ret;\n}\n\nint mutexUnlock(mutex *m) {\n  int ret = pthread_mutex_unlock(m);\n  if (ret) {\n    fprintf(stderr, \"mutexUnlock: pthread_mutex_unlock failed with error %d\\n\",\n      ret);\n  }\n  return ret;\n}\n","sourceCodeStart":19,"sourceCodeEnd":51,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-native-client/src/main/native/libhdfs/os/posix/mutexes.c#L19-L51","documentation":"mutexLock() is libhdfs' wrapper around pthread_mutex_lock; it prints this when the call returns an error instead of blocking: EINVAL (mutex storage not initialized or corrupted), EDEADLK (thread already owns this non-recursive mutex), or EAGAIN (recursion limit on a recursive mutex). The wrapper still returns the error, so callers continue without mutual exclusion held — a correctness hazard beyond the log line.","triggerScenarios":"Recursive locking of jclassInitMutex (a plain PTHREAD_MUTEX_INITIALIZER, non-recursive) from the same thread; a mutex whose storage was reinitialized or overwritten; exceeding recursive depth on jvmMutex (initialized PTHREAD_MUTEX_RECURSIVE by the library constructor).","commonSituations":"Re-entrant call paths through libhdfs from callbacks; heap/stack corruption smashing static mutex storage (EINVAL plus unrelated crashes); unusual static-link or dlopen ordering where the constructor init of jvmMutexAttr never ran.","solutions":["Map the number: EINVAL means uninitialized/corrupted mutex — hunt overruns near the storage with ASan/valgrind; EDEADLK means recursive locking of a non-recursive mutex — restructure the call path","Never call libhdfs APIs re-entrantly from callbacks or signal handlers on a thread that is already inside an HDFS call","If it appears at startup with odd behavior, assume corruption until proven otherwise","Rebuild/upgrade libhdfs if a build-specific init-ordering bug is suspected"],"exampleFix":"/* before */\nmutexLock(&m);\n/* proceeds even when the lock failed */\n\n/* after */\nif (mutexLock(&m) != 0) {\n    return -1;  /* lock NOT held — bail instead of running unsynchronized */\n}\n/* ... */\nmutexUnlock(&m);","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"/* when hacking on libhdfs internals: never ignore the wrapper return */\nif (mutexLock(&m) != 0) {\n    return -1; /* lock NOT held — do not proceed */\n}\n/* critical section */\nmutexUnlock(&m);","preventionTips":["Treat any pthread mutex error as a corruption smoke signal until proven otherwise","Never call libhdfs re-entrantly from callbacks or signal handlers on the same thread","Keep app and libhdfs on matching glibc/pthread versions"],"tags":["libhdfs","pthread","mutex","posix","synchronization"],"backgroundTag":"pthread-mutex-lock-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}