mirror of
https://github.com/home-assistant/supervisor.git
synced 2026-04-27 02:42:42 +00:00
* Let OSError propagate during backup creation Securetar's create_tar context manager uses a two-phase header write: on enter it writes a placeholder tar header (size unknown), and on exit _finalize_tar_entry seeks back to rewrite the header with the actual size. If an OSError (e.g. ENOSPC) occurs mid-write, the inner tar entry is left with truncated data and a placeholder header. Continuing to write more entries on top of this produces a structurally invalid tar file that cannot be restored. Previously, _folder_save wrapped OSError as BackupError, which store_folders then caught and swallowed — allowing the backup to continue writing to an already corrupt outer tar. Similarly, _create_finalize silently swallowed OSError when writing backup.json, and the finally block in create() could raise a secondary OSError from _close_outer_tarfile that replaced the original exception. Securetar already distinguishes read vs write errors: read-side errors (e.g. permission denied on a source file) are wrapped as AddFileError (non-fatal, skip the file), while write-side OSError propagates as-is. With this change, write-side OSError is wrapped as BackupFatalError (a BackupError subclass) instead of plain BackupError. This ensures: - store_folders/store_addons do not swallow it (they only catch BackupError, and re-raise BackupFatalError explicitly). - The job decorator handles it as a HassioError (no extra Sentry event). Letting OSError bubble up raw would cause the job decorator to treat it as an unhandled exception, capturing it to Sentry and wrapping it as JobException — producing more Sentry noise, not less. - _do_backup catches it via `except BackupError` and deletes the incomplete backup file. This is the correct behavior since the tar is structurally corrupt and not restorable. Changes: - Add BackupFatalError exception for write-side I/O errors. - In create(), use except/else instead of finally so that finalization is skipped when an error already occurred during yield. This prevents a secondary exception from _close_outer_tarfile replacing the original error. - In _create_finalize, raise BackupFatalError on OSError instead of swallowing it. - In _folder_save, wrap OSError as BackupFatalError (not BackupError). - In store_folders, re-raise BackupFatalError instead of swallowing. - In store_supervisor_config, wrap OSError as BackupFatalError. Fixes SUPERVISOR-B53 Fixes SUPERVISOR-1FAJ Fixes SUPERVISOR-BJ4 Fixes SUPERVISOR-18KS Fixes SUPERVISOR-1HE6 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Rename BackupFatalError to BackupFatalIOError --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>