sinelaw/fresh · error · SudoSaveRequired

SudoSaveRequired

Error message

SudoSaveRequired

What it means

An in-place save could not write the destination file directly because the process lacks the file owner's privileges (uid/gid/mode mismatch). save.rs:569 raises the structured SudoSaveRequired error (via make_sudo_error, from save_with_inplace_write or write_data_inplace) carrying temp_path, dest_path, uid, gid, and mode so the caller can retry the save with elevated (sudo) privileges.

Solutions

  1. Handle the SudoSaveRequired payload: complete the save using the provided temp_path and elevate (e.g. sudo install -m mode -o uid -g gid temp_path dest_path)
  2. Reopen the editor with elevated privileges (sudo fresh file) for system-owned files
  3. Change ownership/permissions of the file (sudo chown) so your user can write it in place
  4. Save to a writable copy instead of the privileged original
Defensive patterns

Strategy: try-catch

Validate before calling

// Unix: check write ownership before attempting in-place save
let meta = std::fs::metadata(&dest_path)?;
let i_am_owner = unsafe { libc::geteuid() } == meta.uid();
if !i_am_owner { prepare_sudo_save_flow(&dest_path); }

Try / catch

// downcast to the structured error
match editor.save(buffer_id) {
    Err(e) if e.downcast_ref::<SudoSaveRequired>().is_some() => {
        let s = e.downcast_ref::<SudoSaveRequired>().unwrap();
        sudo_complete_save(&s.temp_path, &s.dest_path, s.uid, s.gid, s.mode);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Editing a file owned by root (or another user) as a non-root process and saving in place — the write requires the file's uid/gid/mode to be preserved but the process isn't the owner.

Common situations: Editing /etc config files or root-owned project files in a normal user session; files created by a container as root then edited by the host user; NFS/ACL setups where the effective uid differs from the file owner.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/dfcc8dd48e90b592. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor-core/src/model/buffer/save.rs:569

    #[cfg(unix)]
    let (uid, gid, mode) = if let Some(ref meta) = original_metadata {
        (
            meta.uid.unwrap_or(0),
            meta.gid.unwrap_or(0),
            meta.permissions
                .as_ref()
                .map(|p| p.mode() & 0o7777)
                .unwrap_or(0),
        )
    } else {
        (0, 0, 0)
    };
    #[cfg(not(unix))]
    let (uid, gid, mode) = (0u32, 0u32, 0u32);

    let _ = original_metadata; // suppress unused warning on non-Unix

    anyhow::anyhow!(SudoSaveRequired {
        temp_path,
        dest_path: dest_path.to_path_buf(),
        uid,
        gid,
        mode,
    })
}

View on GitHub (pinned to 67894ca546)