Version
7.4.2 (/app/src/__init__.py in container)
Deployment Method
Docker Compose
Database Type
PostgreSQL
Storage Setup
- Media on Docker volume using JuiceFS (S3 object storage backend)
DEDUPLICATE_MEDIA=true
VERIFY_MEDIA=true
Bug Description
VERIFY_MEDIA re-download repeatedly fails for a subset of media with this recurring pattern:
WARNING - Symlink failed, using direct path: [Errno 17] File exists: '../_shared/<name>' -> '/data/backups/media/<chat_id>/<name>'
ERROR - Error downloading media: [Errno 2] No such file or directory: '/data/backups/media/_shared/<name>'
WARNING - Failed to re-download media for message <id>
This happens after backup completion during media verification/redownload.
What I observed on disk
For failed entries:
- Chat path exists as a dangling symlink:
/data/backups/media/-1002443412147/5956498299518196004_yCSXQMIrYQImig -> ../_shared/5956498299518196004_yCSXQMIrYQImig
- But
_shared has only variant files with extensions/suffixes, e.g.:
5956498299518196004_yCSXQMIrYQImig.mp4
5956498299518196004_yCSXQMIrYQImig (1).mp4
5956498299518196004_yCSXQMIrYQImig (2).mp4
- Exact
_shared/<name> (without extension) is missing.
Current state in this environment:
- 33 dangling symlinks under
media/-1002443412147
- All 33 have extension/suffixed candidates in
_shared
Why this seems to happen (code-path analysis)
In src/telegram_backup.py:
_process_media checks if not os.path.exists(file_path) (around line 1342). For a dangling symlink this is True.
- It attempts
os.symlink(..., file_path) (line ~1362), which raises Errno 17 because the path entry already exists (even though dangling).
- The fallback handles all
OSError by doing shutil.move(shared_file_path, file_path) (line ~1368).
- If Telethon saved to a different final filename (e.g. extension added / conflict suffix),
shared_file_path no longer exists, causing Errno 2.
Also in _verify_and_redownload_media, cleanup uses os.path.exists(file_path) before os.remove (line ~584), so dangling symlinks are not removed before re-download.
Related issue
Likely related symptom family to #30, but this report includes a reproducible verification/redownload path and probable root cause.
Expected Behavior
VERIFY_MEDIA should repair missing/corrupt media without entering repeated Errno 17 + Errno 2 loops.
Suggested Fix (proposal)
- Use
os.path.lexists when deciding whether file_path already exists and before cleanup/removal in verify flow.
- If
lexists(file_path) and path is dangling symlink, unlink it before creating new symlink.
- Treat
EEXIST separately from symlink-unsupported errors:
- for
EEXIST, remove/recreate link if dangling;
- do not immediately fall back to
shutil.move.
- Capture and use the actual return value of
await self.client.download_media(...) as canonical downloaded path (Telethon may append extension or collision suffix).
- Ensure DB
file_name/file_path is updated to the canonical final filename/path actually written on disk.
If useful, I can open a PR with a concrete patch implementing the above.
Version
7.4.2 (
/app/src/__init__.pyin container)Deployment Method
Docker Compose
Database Type
PostgreSQL
Storage Setup
DEDUPLICATE_MEDIA=trueVERIFY_MEDIA=trueBug Description
VERIFY_MEDIAre-download repeatedly fails for a subset of media with this recurring pattern:This happens after backup completion during media verification/redownload.
What I observed on disk
For failed entries:
/data/backups/media/-1002443412147/5956498299518196004_yCSXQMIrYQImig -> ../_shared/5956498299518196004_yCSXQMIrYQImig_sharedhas only variant files with extensions/suffixes, e.g.:5956498299518196004_yCSXQMIrYQImig.mp45956498299518196004_yCSXQMIrYQImig (1).mp45956498299518196004_yCSXQMIrYQImig (2).mp4_shared/<name>(without extension) is missing.Current state in this environment:
media/-1002443412147_sharedWhy this seems to happen (code-path analysis)
In
src/telegram_backup.py:_process_mediachecksif not os.path.exists(file_path)(around line 1342). For a dangling symlink this isTrue.os.symlink(..., file_path)(line ~1362), which raisesErrno 17because the path entry already exists (even though dangling).OSErrorby doingshutil.move(shared_file_path, file_path)(line ~1368).shared_file_pathno longer exists, causingErrno 2.Also in
_verify_and_redownload_media, cleanup usesos.path.exists(file_path)beforeos.remove(line ~584), so dangling symlinks are not removed before re-download.Related issue
Likely related symptom family to #30, but this report includes a reproducible verification/redownload path and probable root cause.
Expected Behavior
VERIFY_MEDIAshould repair missing/corrupt media without entering repeatedErrno 17+Errno 2loops.Suggested Fix (proposal)
os.path.lexistswhen deciding whetherfile_pathalready exists and before cleanup/removal in verify flow.lexists(file_path)and path is dangling symlink, unlink it before creating new symlink.EEXISTseparately from symlink-unsupported errors:EEXIST, remove/recreate link if dangling;shutil.move.await self.client.download_media(...)as canonical downloaded path (Telethon may append extension or collision suffix).file_name/file_pathis updated to the canonical final filename/path actually written on disk.If useful, I can open a PR with a concrete patch implementing the above.