Potential Race Condition Fix - OS Rename & Chmod - PermissionError by DEKHTIARJonathan · Pull Request #115 · gitpython-developers/gitdb
There is a really flaky and hard to debug bug when using gitdb at least on MacOS (M-Processor) using Docker (docker.io/python:3.13 image).
I have only been able to reproduce this error within pytest on my laptop (Apple M4 laptop).
I completely randomly get:
repo = Repo(........) # Repo Created using `GitPython` [...] repo.index.add("*") ~~~~~~~~~~~~~~^^^^^ File "/usr/local/lib/python3.13/site-packages/git/index/base.py", line 885, in add entries_added.extend(self._entries_for_paths(paths, path_rewriter, fprogress, entries)) ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/git/util.py", line 176, in wrapper return func(self, *args, **kwargs) File "/usr/local/lib/python3.13/site-packages/git/index/util.py", line 111, in set_git_working_dir return func(self, *args, **kwargs) File "/usr/local/lib/python3.13/site-packages/git/index/base.py", line 745, in _entries_for_paths entries_added.append(self._store_path(filepath, fprogress)) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.13/site-packages/git/index/base.py", line 698, in _store_path istream = self.repo.odb.store(IStream(Blob.type, st.st_size, stream)) File "/usr/local/lib/python3.13/site-packages/gitdb/db/loose.py", line 233, in store chmod(obj_path, self.new_objects_mode) ~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PermissionError: [Errno 1] Operation not permitted: '/git_projects/<GIT_PROJECT_NAME>/.git/objects/9d/961f54d04e15cef0e525d1cb3d937bd7b82b04'
When you inspect a little bit that obj_path - everything looks absolutely fine as far as I can tell. I have no idea what could trigger this PermissionError. The script is executing under the user dev-user:dev-user of UID/GID: 1000:1000
os.getuid()=1000 pwd.getpwuid(os.getuid())=pwd.struct_passwd(pw_name='dev-user', pw_passwd='x', pw_uid=1000, pw_gid=1000, pw_gecos='', pw_dir='/home/dev-user', pw_shell='/bin/bash') os.stat(obj_path)=os.stat_result(st_mode=33152, st_ino=3713822, st_dev=65025, st_nlink=1, st_uid=1000, st_gid=1000, st_size=473, st_atime=1734989354, st_mtime=1734989354, st_ctime=1734989354) Path(obj_path).exists()=True Path(obj_path).owner()='dev-user' Path(obj_path).group()='dev-user'
So clearly something is not going well.
Looking a little bit more in detail, turns out the error is always happening in scenario B - but not systematically in scenario B:
if isfile(obj_path): remove(tmp_path) print("SCENARIO A !!!!!!!!!!!!!!!") else: rename(tmp_path, obj_path) print("SCENARIO B !!!!!!!!!!!!!!!")
There might be an interference between tempfile.mkstemp, os.rename and os.chmod. Not sure which one.
It seems like a retry loop with a small temporization seems to mitigate the problem.
One supposition is that os.rename might not entirely complete by the time it returns. Or some file descriptors might be corrupted. Unfortunately, it's really really hard for me to debug and I'm not sure even what to look for.