{"record":{"id":"e055974f73be3dda","repo":"xai-org/x-algorithm","slug":"lock-file-parent-directory-does-not-exist-lock-f","errorCode":null,"errorMessage":"Lock file parent directory does not exist: {lock_file.parent}","messagePattern":"Lock file parent directory does not exist: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"phoenix/xrex/utils/aot.py","lineNumber":422,"sourceCode":"        assert source.dtype == np.uint8\n        buf = source\n    return _replicate(buf)\n\n\n@contextmanager\ndef RetryFileLock(lock_file: Path, *, poll_interval: float):\n    assert poll_interval > 0, f\"require {poll_interval=} > 0\"\n    lock = filelock.FileLock(lock_file, timeout=-1, poll_interval=poll_interval)\n\n    while True:\n        try:\n            lock.acquire()\n            break\n        except OSError as e:\n            if e.errno not in (errno.ENOLCK, errno.ESTALE, errno.ENOENT):\n                raise\n            if e.errno == errno.ENOENT and not lock_file.parent.exists():\n                raise FileNotFoundError(\n                    f\"Lock file parent directory does not exist: {lock_file.parent}\"\n                ) from e\n            logger.warning(\n                \"Transient error acquiring lock %s: %s. Retrying...\",\n                lock_file,\n                e,\n            )\n            time.sleep(poll_interval)\n        except NotImplementedError as e:\n            if \"use SoftFileLock instead\" in str(e):\n                logger.warning(\n                    \"FileSystem does not appear to support flock. Falling back to SoftFileLock for %s\",\n                    lock_file,\n                )\n                lock = filelock.SoftFileLock(lock_file, timeout=-1, poll_interval=poll_interval)\n            else:\n                raise\n","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/phoenix/xrex/utils/aot.py#L404-L440","documentation":"RetryFileLock retries transient OSError (ENOLCK/ESTALE/ENOENT) while acquiring a file lock, but if the error is ENOENT because the lock file's parent directory no longer exists, retrying is pointless and FileNotFoundError is raised immediately naming the missing directory.","triggerScenarios":"Acquiring the AOT cache lock when the cache directory (or an ancestor like a job scratch dir) was deleted concurrently — e.g. cleanup scripts racing the job, or NFS stale mounts — between lock creation and acquisition.","commonSituations":"Shared caches on NFS/Lustre with aggressive purgers; tmpwatch deleting /tmp hierarchies mid-run; concurrent jobs where one removes the cache dir.","solutions":["Recreate the cache directory before acquiring: aot_cache_dir.mkdir(parents=True, exist_ok=True)","Disable or scope cleanup jobs that purge the cache directory during runs","Use a stable, dedicated cache directory not under /tmp or auto-purged scratch"],"exampleFix":"# before\nlock = RetryFileLock(aot_cache_dir / 'lock')\n# after\naot_cache_dir.mkdir(parents=True, exist_ok=True)\nlock = RetryFileLock(aot_cache_dir / 'lock')","handlingStrategy":"retry","validationCode":"from pathlib import Path\nPath(aot_cache_dir).mkdir(parents=True, exist_ok=True)  # before acquiring lock","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        with RetryFileLock(lock_file):\n            ... \n        break\n    except FileNotFoundError:\n        lock_file.parent.mkdir(parents=True, exist_ok=True)  # recreate and retry","preventionTips":["mkdir the cache dir before every lock acquisition","Never place caches under auto-purged /tmp or scratch","Exclude cache dirs from cleanup/retention scripts"],"tags":["file-lock","filesystem","cache","concurrency"],"backgroundTag":"directory-missing","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}