Skip to content

Conflicts File Safety and Recovery

QenTerra edited this page Jul 29, 2026 · 1 revision

Conflicts, File Safety, and Recovery

Unspool treats a destination collision as a decision, not as permission.

Conflict actions

Action Result
Skip Leave the existing file untouched and record a conflict outcome
Replace Atomically replace the exact destination after explicit selection
Save a Copy Create a new name such as name — copy.ext, then increment only when needed

Skip is always the default. Replace and Save a Copy are available per file and as deliberate “all conflicts” actions in the preflight sheet.

An ordinary download never silently overwrites a file and never silently adds a numeric suffix. Copy naming happens only after the user chooses Save a Copy.

Same-batch collisions

Preflight tracks planned standardized paths. If two selected Telegram files would use the same path, the second is treated as a conflict even if no file currently exists on disk. Telegram file ID deduplication also prevents the same Telegram file from appearing twice in a batch.

Unsafe filenames

The destination layer accepts a filename only as one path component. Unsafe values fail with a typed invalidFilename error. Unspool does not “fix” the attachment name behind the user's back because that would violate filename provenance.

Chat titles are different: when per-chat folders are enabled, the title is converted into a safe directory name because it is an organizational label, not the source filename.

Capacity and size checks

Preflight compares the total of known attachment sizes with the destination volume's available capacity. Unknown capacity does not fabricate an error, but known insufficient capacity blocks the batch.

After TDLib completes a file, placement compares its local file size with Telegram's expected size when available. A mismatch fails before final placement.

Atomic placement

New files are copied to a hidden .partial path in the destination directory and then moved to the final name. Replacement uses a hidden replacement path and the filesystem replacement API. Temporary files are removed on failure when possible.

This minimizes, but cannot mathematically eliminate, the chance of exposing a partially written final file during interruption.

Pause and resume

Pause stops scheduling new files. Already running TDLib downloads are allowed to reach an outcome, so the state can briefly be Pausing before it becomes Paused. Resume permits scheduling again.

Cancellation

Cancellation:

  • marks the batch as cancelling;
  • sends cancelDownloadFile for active Telegram file IDs;
  • cancels running child tasks;
  • records pending items as cancelled;
  • preserves already completed files.

The UI asks for confirmation because cancellation does not roll back files that already reached the destination.

Relaunch recovery

If the application relaunches with pending-download.json, Downloads offers:

  • Resume — restore the batch selection and its conflict choices, then run a fresh preflight against current disk state;
  • Discard — remove the pending record without deleting files.

Fresh preflight is important: available capacity and filename conflicts may have changed while the app was closed.

Clone this wiki locally