hermes - 💡(How to fix) Fix _restore_file_mode no-ops on new files, leaving atomic_json_write outputs at 0o600

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Fix Action

Fix / Workaround

This is a one-line change with minimal blast radius. The mode 0o644 is the standard default for new files on Linux and matches what users expect
from a file-writing utility.
Workaround

RAW_BUFFERClick to expand / collapse
 atomic_json_write (and atomic_yaml_write) use tempfile.mkstemp() to create a temporary file, then os.replace() it to the target path. mkstemp            
 defaults to mode 0o600 (owner-only). After the atomic replace, _restore_file_mode() is called to restore the original file permissions — but only if     
 the file already existed. For new files, _preserve_file_mode() returns None, and _restore_file_mode() returns immediately:                               
                                                                                                                                                          
 python                                                                                                                                                   
 def _restore_file_mode(path: Path, mode: "int | None") -> None:                                                                                          
     if mode is None:                                                                                                                                     
         return          # ← no-op for new files                                                                                                          
     ...                                                                                                                                                  
                                                                                                                                                          
 This means every file first created by atomic_json_write or atomic_yaml_write is permanently stuck at 0o600.                                             
 Impact                                                                                                                                                   
                                                                                                                                                          
 - gateway_state.json (written by gateway/status.py:_write_json_file) — becomes 0o600 root-owned. The dashboard process, running as a non-root user,      
 calls is_gateway_runtime_lock_active() which opens this file with "a+" mode (requires write permission for fcntl.flock), triggering PermissionError      
 [Errno 13]. Dashboard /api/status returns HTTP 500 — blank status panel.                                                                                 
 - Any other file created for the first time by the ~30+ callers of atomic_json_write and the ~15+ callers of atomic_yaml_write — session                 
 checkpoints, model caches, config files, etc. — inherits the same restrictive mode until manually chmod'ed.                                              
 - Particularly problematic in Docker deployments where gateway runs as root and the dashboard/web UI runs as a different user.                           
 Affected files                                                                                                                                           
                                                                                                                                                          
 - utils.py:44-54 — _restore_file_mode() (link)                                                                                                           
 - utils.py:89-132 — atomic_json_write() calls _preserve_file_mode then _restore_file_mode (link)                                                         
 - utils.py:143-... — atomic_yaml_write() has the same pattern                                                                                            
 Proposed fix                                                                                                                                             
                                                                                                                                                          
 In _restore_file_mode(), default to 0o644 instead of no-oping when mode is None:                                                                         
                                                                                                                                                          
 python                                                                                                                                                   
 def _restore_file_mode(path: Path, mode: "int | None") -> None:                                                                                          
     if mode is None:                                                                                                                                     
         mode = 0o644          # ← new files: world-readable, owner-writable                                                                              
     try:                                                                                                                                                 
         os.chmod(path, mode)                                                                                                                             
     except OSError:                                                                                                                                      
         pass                                                                                                                                             
                                                                                                                                                          
 This is a one-line change with minimal blast radius. The mode 0o644 is the standard default for new files on Linux and matches what users expect         
 from a file-writing utility.                                                                                                                             
 Workaround                                                                                                                                               
                                                                                                                                                          
 Until a fix ships, non-root processes that need to read these files can either:                                                                          
 - Manually chmod 644 after gateway starts                                                                                                                
 - Or modify _restore_file_mode locally (the change survives hermes update only until the next update)                                                    
 Environment                                                                                                                                              
                                                                                                                                                          
 - Hermes Agent v0.13.0 (2026.5.7)                                                                                                                        
 - Docker deployment (Synology NAS)                                                                                                                       
 - Gateway runs as root, dashboard as non-root user

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING