Skip to content

fix: preserve container bundles on load failure; write bundle files atomically#1859

Open
radheradhe01 wants to merge 1 commit into
apple:mainfrom
radheradhe01:fix/no-bundle-delete-on-load-error
Open

fix: preserve container bundles on load failure; write bundle files atomically#1859
radheradhe01 wants to merge 1 commit into
apple:mainfrom
radheradhe01:fix/no-bundle-delete-on-load-error

Conversation

@radheradhe01

@radheradhe01 radheradhe01 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

ContainersService.loadAtBoot wraps each container load in a do/catch, and the catch runs try? FileManager.default.removeItem(at: dir) — deleting the entire on-disk bundle on any error. Some of those errors are transient and unrelated to bundle integrity. For example, a runtime plugin that is not yet registered throws internalError, which then destroys the user's container directory.

A contributing root cause: Bundle.write persists JSON with a plain data.write(to:) (non-atomic). A crash or power loss mid-write can leave a truncated file that fails to decode on the next boot — which then triggers the deletion path above, turning a recoverable torn write into permanent data loss.

This change:

  • Bundle.write now writes with .atomic, so an interrupted write cannot leave a corrupt file behind.
  • loadAtBoot no longer deletes the bundle on load errors; it logs and leaves the bundle on disk so a transient failure (e.g. a plugin that registers later) does not cause data loss.

No behavior change on the success path.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

Verified by static / code-level review; not built locally (no macOS 26 toolchain available here) — CI build will validate.

… atomically

### Problem
`ContainersService.loadAtBoot` wraps each container load in a `do/catch`, and the `catch` runs `try? FileManager.default.removeItem(at: dir)` — deleting the entire on-disk bundle on **any** error. Some of those errors are transient and unrelated to bundle integrity. For example, a runtime plugin that is not yet registered throws `internalError`, which then destroys the user's container directory.

A contributing root cause: `Bundle.write` persists JSON with a plain `data.write(to:)` (non-atomic). A crash or power loss mid-write can leave a truncated file that fails to decode on the next boot — which then triggers the deletion path above, turning a recoverable torn write into permanent data loss.

### Fix
- `Bundle.write`: write with `.atomic`, so an interrupted write cannot leave a corrupt file behind.
- `loadAtBoot`: stop deleting the bundle on load errors. Log and leave the bundle on disk so a transient failure (e.g. a plugin that registers later) does not cause data loss.

### Notes
No behavior change on the success path.
@radheradhe01 radheradhe01 changed the title Don't delete container bundles when loading fails; write bundle files atomically fix: preserve container bundles on load failure; write bundle files atomically Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant