Skip to content

Checkpoint writes are not atomic, a crash mid save destroys the previous one #13

Closed

Description

@CanReader

src/serialize/checkpoint.rs:79 and src/serialize/safetensors.rs:78:

let mut out = BufWriter::new(File::create(path)?);

File::create truncates immediately. And the usage pattern we document in
serialize/training.rs is overwriting one path every N steps:

if step % 500 == 0 { save_training(&model, &opt, step, "run.fdl")?; }

A kill, an OOM, or a full disk during that write leaves a truncated run.fdl and
no copy of the good one. This module exists specifically to survive a long
unattended run and this is the one failure it doesn't survive. There's also no
fsync before returning, so a power cut can leave a file that looks complete and
isn't.

Write to path.tmp, sync_all(), then rename (atomic on the same filesystem).
Worth a robustness test that truncates a checkpoint and asserts the previous one
still loads.

Activity

  1. sharmis-tp commented on Nov 10, 2026

    @sharmis-tp
    Contributor

    I'd like to take this. I used the same write-to-partial, sync_all, rename pattern in #72 for the MNIST cache; the checkpoint and safetensors writers need the same treatment. I'll have a PR up shortly.

  2. added a commit that references this issue on Nov 12, 2026
    4703f92
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Wrong numbers or lost dataarea:serializebugSomething isn't workinggood first issueGood for newcomershelp wantedExtra attention is needed

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions