Skip to content

fix: guard fcntl.flock(LOCK_UN) with try/except in 5 files#27909

Open
vanthinh6886 wants to merge 1 commit into
NousResearch:mainfrom
vanthinh6886:fix/unguarded-flock-unlock
Open

fix: guard fcntl.flock(LOCK_UN) with try/except in 5 files#27909
vanthinh6886 wants to merge 1 commit into
NousResearch:mainfrom
vanthinh6886:fix/unguarded-flock-unlock

Conversation

@vanthinh6886

Copy link
Copy Markdown
Contributor

Problem

On POSIX systems, fcntl.flock(LOCK_UN) can raise OSError (e.g. EBADF if the fd was already closed, or EINTR on signal delivery). When this happens inside a finally block, the subsequent fd.close() is skipped — leaking the file descriptor and potentially holding the lock indefinitely.

The msvcrt (Windows) path in all these files already wraps the unlock in try/except, but the fcntl path did not. This inconsistency means the bug only manifests on Linux/macOS.

Fix

Wrap fcntl.flock(lock_fd, fcntl.LOCK_UN) in try: ... except (OSError, IOError): pass to match the existing msvcrt pattern. Zero behavioral change on the happy path; prevents fd leaks and exception masking on the error path.

Files Changed

File Context
tools/environments/file_sync.py sync_back file lock
tools/memory_tool.py memory write lock
tools/skill_usage.py skill usage tracking lock
cron/scheduler.py tick lock
hermes_cli/auth.py credential pool lock

Before vs After

Scenario Before After
flock(LOCK_UN) raises OSError fd.close() skipped -> fd leak + lock held forever Exception caught, fd.close() runs normally
flock(LOCK_UN) succeeds Works normally Works normally (no change)

Tests

Existing tests cover the happy path. The error path is hard to trigger deterministically (requires fd invalidation or signal delivery during unlock), but the fix is defensive and follows the same pattern already used for the msvcrt branch in each file.

On POSIX systems, fcntl.flock(LOCK_UN) can raise OSError (e.g. EBADF
if the fd was already closed by another thread, or EINTR on signal
delivery). When this happens in a finally block, the subsequent
fd.close() is skipped, leaking the file descriptor and potentially
holding the lock indefinitely.

The msvcrt (Windows) path in all these files already wraps the unlock
in try/except, but the fcntl path did not — an inconsistency that
this commit fixes.

Files fixed:
- tools/environments/file_sync.py (sync_back lock)
- tools/memory_tool.py (memory write lock)
- tools/skill_usage.py (skill usage tracking lock)
- cron/scheduler.py (tick lock)
- hermes_cli/auth.py (credential pool lock)
@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management tool/memory Memory tool and memory providers area/auth Authentication, OAuth, credential pools duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have labels May 18, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #16274 — same 5 files, same fix (wrap fcntl.flock(LOCK_UN) in try/except OSError). Also duplicates #21719, #20529, #23819, #23873. #16274 is the canonical PR.

@BoardJames-Bot

Copy link
Copy Markdown

Board James triage pass: this PR's check-attribution failure is the same missing-author-map issue as #27910/#27913: vanthinh6886@gmail.com (vanthinh6886) is not in scripts/release.py AUTHOR_MAP. I opened #27931 with the central fix ("vanthinh6886@gmail.com": "vanthinh6886"). The test job did not expose a branch-local assertion failure in logs; it was cancelled at ~95% progress. After #27931 lands, please rebase/rerun checks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/cron Cron scheduler and job management duplicate This issue or pull request already exists P3 Low — cosmetic, nice to have tool/memory Memory tool and memory providers type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants