{"record":{"id":"26f865d9c31a49da","repo":"swc-project/swc","slug":"failed-to-create-global-mutex-named","errorCode":null,"errorMessage":"failed to create global mutex named `{}`: {}","messagePattern":"failed to create global mutex named `(.+?)`: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/swc_common/src/errors/lock.rs","lineNumber":83,"sourceCode":"\n    impl Drop for Guard {\n        fn drop(&mut self) {\n            unsafe {\n                ReleaseMutex((self.0).0);\n            }\n        }\n    }\n\n    let cname = CString::new(name).unwrap();\n    unsafe {\n        // Create a named mutex, with no security attributes and also not\n        // acquired when we create it.\n        //\n        // This will silently create one if it doesn't already exist, or it'll\n        // open up a handle to one if it already exists.\n        let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr() as *const u8);\n        if mutex.is_null() {\n            panic!(\n                \"failed to create global mutex named `{}`: {}\",\n                name,\n                io::Error::last_os_error()\n            );\n        }\n        let mutex = Handle(mutex);\n\n        // Acquire the lock through `WaitForSingleObject`.\n        //\n        // A return value of `WAIT_OBJECT_0` means we successfully acquired it.\n        //\n        // A return value of `WAIT_ABANDONED` means that the previous holder of\n        // the thread exited without calling `ReleaseMutex`. This can happen,\n        // for example, when the compiler crashes or is interrupted via ctrl-c\n        // or the like. In this case, however, we are still transferred\n        // ownership of the lock so we continue.\n        //\n        // If an error happens.. well... that's surprising!","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_common/src/errors/lock.rs#L65-L101","documentation":"On Windows, swc_common synchronizes processes with a named global mutex created via CreateMutexA (for example to lock stdout/stderr across processes). If the OS returns a null handle, the code panics with the mutex name and io::Error::last_os_error(). This is an environment-level kernel-object allocation failure, not a logic error in user code.","triggerScenarios":"Running on Windows when CreateMutexA fails: exhausted handle quota or nonpaged memory, a sandbox/container restricting named-kernel-object creation, or a heavily loaded CI host. The mutex is created without security attributes and not pre-acquired, so only OS-level failures reach this branch.","commonSituations":"Windows CI runners under memory/handle pressure, test sandboxes and Windows containers that deny global kernel object namespaces, terminal multiplexers (mintty/conda) that alter the process environment, Wine-based environments.","solutions":["Retry the operation: transient resource exhaustion on Windows commonly clears after backoff","Reduce concurrent SWC processes on the machine to lower handle/memory pressure","Run the build outside the restricted sandbox or container that blocks named mutex creation","If persistent, capture the reported OS error code and report an issue with environment details"],"exampleFix":"// before\nlet _guard = swc_common::errors::lock(); // panics: failed to create global mutex\n\n// after: treat as a transient OS failure with bounded retries\nuse std::panic::{catch_unwind, AssertUnwindSafe};\nuse std::thread::sleep;\nuse std::time::Duration;\nlet guard = (0..3)\n    .map(|_| catch_unwind(AssertUnwindSafe(swc_common::errors::lock)))\n    .find_map(|g| match g {\n        Ok(g) => Some(g),\n        Err(_) => { sleep(Duration::from_millis(100)); None }\n    });\nassert!(guard.is_some(), \"global mutex still failing after retries\");","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"use std::panic::{catch_unwind, AssertUnwindSafe};\nuse std::{thread::sleep, time::Duration};\nlet mut guard = None;\nfor attempt in 0..3 {\n    if let Ok(g) = catch_unwind(AssertUnwindSafe(swc_common::errors::lock)) {\n        guard = Some(g);\n        break;\n    }\n    sleep(Duration::from_millis(100 * (attempt + 1)));\n}\nif guard.is_none() { /* report OS resource exhaustion instead of crashing */ }","preventionTips":["Limit concurrent SWC worker processes on Windows hosts to reduce handle/memory pressure","Avoid sandboxes that block named kernel objects for build processes","Monitor handle counts in CI to catch quota exhaustion before it panics"],"tags":["windows","mutex","os-resources","panic","platform-specific"],"backgroundTag":"os-resource-allocation-failed","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}