dgtlmoon/changedetection.io · critical · OSError
I/O error saving {label}: {e}
Error message
I/O error saving {label}: {e} What it means
The fallback OSError raised by save_json_atomic for any write error that is neither ENOSPC (28) nor EDQUOT (122). The original exception is chained ('from e') and its message embedded, so the real underlying I/O problem (permissions, path issues, hardware errors) is preserved.
Source
Thrown at changedetectionio/store/file_saving_datastore.py:161
# Cleanup temp file
if not fd_closed:
try:
os.close(fd)
except:
pass
if os.path.exists(temp_path):
try:
os.unlink(temp_path)
except:
pass
# Provide helpful error messages
if e.errno == 28: # ENOSPC
raise OSError(f"Disk full: Cannot save {label}") from e
elif e.errno == 122: # EDQUOT
raise OSError(f"Disk quota exceeded: Cannot save {label}") from e
else:
raise OSError(f"I/O error saving {label}: {e}") from e
except Exception as e:
# Cleanup temp file
if not fd_closed:
try:
os.close(fd)
except:
pass
if os.path.exists(temp_path):
try:
os.unlink(temp_path)
except:
pass
raise e
def save_entity_atomic(entity_dir, uuid, entity_dict, filename, entity_type, max_size_mb):
"""View on GitHub (pinned to 5d9c7c6da7)
Solutions
- Read the appended ': {e}' — it contains errno/strerror pinpointing the cause
- Fix ownership/permissions: chown -R <app-user> <datastore-path> && chmod u+w
- Confirm the datastore directory exists and the mount is healthy (NFS/SMB not stale)
- If disk hardware errors appear (EIO/medium error), move data off and replace/check the disk
Defensive patterns
Strategy: try-catch
Validate before calling
import os path = datastore_path assert os.path.isdir(path) and os.access(path, os.W_OK), 'datastore not writable'
Try / catch
try:
datastore._save_settings()
except OSError as e:
logger.critical('settings save failed: %s (errno attached via __cause__)', e)
# inspect e.__cause__ for the original errno (EACCES/EIO/ENOENT) Prevention
- Run the app under a single fixed user; never mix root/non-root runs on the same datastore
- Smoke-test writability at startup with a temp-file create/delete
- Mount the datastore on reliable storage; stale NFS mounts surface here as generic I/O errors
When it happens
Trigger: Atomic save failing with e.g. EACCES (datastore dir not writable / ownership changed after running as a different user), ENOENT (datastore path deleted or never created), EIO (failing disk/NFS stale handle), or EBADF on a closed descriptor during write.
Common situations: Running the container once as root then again as a non-root user, leaving root-owned files; bind-mount misconfiguration where the host dir has wrong perms; NAS/SMB mounts dropping; datastore directory removed while the app ran.
Related errors
- Disk full: Cannot save {label}
- Disk quota exceeded: Cannot save {label}
- Migration failed: Could not save watch {uuid}. url-watches.j
- Migration failed: {len(missing)} watch files missing: {missi
- Migration failed: Could not create changedetection.json. url
AI-assisted analysis of dgtlmoon/changedetection.io@5d9c7c6da7 (2026-08-27).
Data as JSON: /api/errors/b936206a6172ca7e.
Report an issue: GitHub.