Interrupted saveRDS in RStudio leaves a truncated output file with no rollback
26.5K reputation · 18 Mar 2024, 10:34 UTC
When a long-running R session in RStudio is interrupted — for example the R process is killed or the session crashes partway through a large saveRDS or write.csv call — a partially written output file can remain on disk. My understanding is that the RStudio IDE provides no transactional or idempotent write semantics for user code, and no automatic rollback of the incomplete file, so the truncated artifact looks like a valid output unless something downstream detects it.
The goal is a reliable pattern for project scripts so that an interrupted write never silently replaces a previously good output, without relying on IDE behavior that may not exist. Constraints: the pattern should work the same across RStudio Desktop and Server/Workbench sessions, should not depend on the Git pane (which versions source, not large generated outputs), and should be verifiable by deliberately killing R mid-write and inspecting the result.
Is it correct that RStudio itself offers no recovery or cleanup for partially written files, leaving this entirely to user code? Is writing to a temporary file followed by an atomic rename the accepted approach, and does file.rename behave atomically on the network filesystems common in Workbench deployments? Are there documented R functions or packages that already wrap this pattern?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
26,525 reputation · 18 Mar 2024, 21:54 UTC
Windows File Locking and Overwrites
While the write-to-temp-then-rename pattern is the standard approach, it is important to note a platform-specific nuance regarding file.rename(). On many Windows configurations, file.rename() will return FALSE and fail to replace the destination if the target file already exists.
Practical Implementation Detail
To ensure the pattern works reliably across both POSIX and Windows environments without relying on external packages, you may need to explicitly remove the target file if the rename fails:
# Ensure the target is replaced on Windows
if (!file.rename(tmp, path)) {
unlink(path)
if (!file.rename(tmp, path)) {
stop("Atomic rename failed after target removal")
}
}
This ensures that the "rollback" is effectively handled by the fact that the original file is only touched after the temporary file has been successfully written to disk. Verification can be performed by attempting to overwrite an existing RDS file and interrupting the process mid-write.