Hmbown/CodeWhale · warning · io::Error

The file changed after the selected change record. Refresh…

Error message

The file changed after the selected change record. Refresh and review it before restoring; nothing was changed.

What it means

restore_file_if_unchanged (crates/tui/src/snapshot/repo.rs:774) computes the sha256 of the live workspace file (or the literal "absent") and compares it to the hash recorded with the selected change record. On mismatch it returns a WouldBlock error and performs no write — a last-writer-wins guard ensuring the user reviews what they are about to overwrite. Nothing is modified when this fires.

Solutions

  1. Refresh the change record / re-open the restore picker so hashes are recomputed against current content.
  2. Review the file's current content; if the local edits should be kept, cancel the restore.
  3. If overwriting is intended, force or re-select the change so the expected hash matches current state, then restore.
Defensive patterns

Strategy: try-catch

Validate before calling

fn hash_matches(ws: &Path, rel: &Path, expected: &str) -> std::io::Result<bool> {
    let actual = match std::fs::read(ws.join(rel)) {
        Ok(bytes) => format!("sha256:{}", sha256_hex(bytes)),
        Err(_) => "absent".to_string(),
    };
    Ok(actual == expected)
}

Try / catch

match restore_result {
    Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
        // file changed since the change record: refresh picker, re-review
    }
    other => other?,
}

Prevention

When it happens

Trigger: Restoring a path whose current file content (or absence) differs from the hash captured when the change record was created — the file was edited, regenerated, or deleted/recreated after the snapshot entry was recorded.

Common situations: Editing a file between the snapshot and an /undo-style restore; a build step rewriting the file; running the restore from a different branch/checkout than where the change was made.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/d811eae517dbb813. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/snapshot/repo.rs:774

    ) -> io::Result<Vec<PathRestoreOutcome>> {
        self.restore_paths_checked(id, rel_paths, || Ok(()))
    }

    pub fn restore_file_if_unchanged(
        &self,
        id: &SnapshotId,
        rel: &Path,
        expected_hash: &str,
    ) -> io::Result<Vec<PathRestoreOutcome>> {
        let verify = || {
            let actual = if self.validate_restore_file(rel)? {
                let bytes = std::fs::read(self.work_tree.join(rel))?;
                format!("sha256:{}", crate::hashing::sha256_hex(bytes))
            } else {
                "absent".to_string()
            };
            if actual != expected_hash {
                return Err(io::Error::new(
                    io::ErrorKind::WouldBlock,
                    "The file changed after the selected change record. Refresh and review it before restoring; nothing was changed.",
                ));
            }
            Ok(())
        };
        verify()?;
        self.restore_paths_checked(id, &[rel.to_path_buf()], verify)
    }

    fn restore_paths_checked(
        &self,
        id: &SnapshotId,
        rel_paths: &[PathBuf],
        preflight: impl FnOnce() -> io::Result<()>,
    ) -> io::Result<Vec<PathRestoreOutcome>> {
        if rel_paths.is_empty() {
            return Ok(Vec::new());

View on GitHub (pinned to 73e0f67d83)