{"record":{"id":"a7d0f4ab8f32be20","repo":"apache/hadoop","slug":"mutexunlock-pthread-mutex-unlock-failed-with-erro","errorCode":null,"errorMessage":"mutexUnlock: pthread_mutex_unlock failed with error %d\n","messagePattern":"mutexUnlock: pthread_mutex_unlock 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":46,"sourceCode":"__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":28,"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#L28-L51","documentation":"mutexUnlock() wraps pthread_mutex_unlock and prints this when unlocking fails: EPERM (calling thread does not own the mutex) or EINVAL (mutex not initialized). Because the wrapper only logs and returns, the mutex remains locked — subsequent lockers deadlock, so this line usually precedes a hang.","triggerScenarios":"Unlocking jvmMutex or jclassInitMutex from a thread other than the one that locked it; unlocking after the storage was reinitialized (EINVAL); error paths that reach an extra unlock.","commonSituations":"Hand-off designs where thread A locks and thread B unlocks; cleanup code that unlocks on a path where the lock was already released; corruption of static mutex storage.","solutions":["Map the code: EPERM — find the real owner with gdb (thread apply all bt) and make lock/unlock happen on the same thread","Audit every early-return path between the matching mutexLock and this unlock for missing or duplicate unlocks","If EINVAL, check for double init/destroy of the mutex and run ASan for overruns near it","After fixing, verify under load that no follow-on deadlock remains (the lock was left held)"],"exampleFix":"/* before: multiple returns, unlock paths diverge */\nmutexLock(&m);\nif (err) return;      /* lock leaked */\ndo_work();\nmutexUnlock(&m);\n\n/* after: single exit guarantees pairing */\nmutexLock(&m);\nif (!err) do_work();\nmutexUnlock(&m);","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"/* single exit point keeps lock/unlock paired */\nmutexLock(&m);\nret = do_work();\nmutexUnlock(&m);\nreturn ret;","preventionTips":["Lock and unlock on the same thread; never hand a held mutex across threads","Use single-exit blocks (or goto cleanup) so early returns cannot skip or double the unlock","Watch for the follow-on deadlock: this message means the mutex stayed locked"],"tags":["libhdfs","pthread","mutex","posix","deadlock"],"backgroundTag":"pthread-mutex-unlock-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}