sinelaw/fresh · error
Buffer has unsaved changes
Error message
Buffer has unsaved changes
What it means
close_buffer refuses to close a buffer whose document has unsaved modifications. buffer_close.rs:44 checks state.buffer.is_modified() for the buffer in the active window and returns this error instead of discarding edits. It's a deliberate safety gate; close_buffer_internal (or force-close variants) bypass it.
Solutions
- Save the buffer first (or prompt the user to save/discard) before closing
- Use the force-close API that skips the modified check when discarding edits is intended
- Check buffer.is_modified() before calling close_buffer and branch to a save/discard dialog
Example fix
// before
editor.close_buffer(id)?; // errors when dirty
// after
if editor.is_buffer_modified(id)? {
editor.save_buffer(id)?; // or prompt user
}
editor.close_buffer(id)?; Defensive patterns
Strategy: validation
Validate before calling
if editor.is_buffer_modified(id)? {
// prompt: Save / Discard / Cancel
prompt_save_before_close(id)?;
} Try / catch
match editor.close_buffer(id) {
Err(e) if e.to_string() == "Buffer has unsaved changes" => {
editor.save_buffer(id)?;
editor.close_buffer(id)?;
}
other => other,
} Prevention
- Check is_modified() before any programmatic close
- Route user-facing closes through a save/discard prompt
- Use force-close only when discarding is explicitly intended
When it happens
Trigger: Calling close_buffer (directly or via close_tab_in_split, preview_file, dismiss_preview, handle_close_buffer, handle_close_terminal) while the target buffer's modified flag is set.
Common situations: User closes a tab with unsaved edits and no save-prompt path ran; scripted/automated tab cleanup hitting dirty buffers; preview close paths when the preview buffer was edited.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot reload: buffer has unsaved modifications
- Buffer range out of bounds: requested
- Buffer has no file path
- Line indexing not available for this document
- Invalid range: start offset
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/8a92cd0ea1b12240.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/app/buffer_close.rs:44
/// Set when the LRU landing target was a buffer *group* rather than a
/// buffer: `buffer` is then only housekeeping and the caller re-activates
/// the group tab on this leaf.
return_to_group: Option<LeafId>,
}
impl Editor {
/// Close the given buffer
pub fn close_buffer(&mut self, id: BufferId) -> anyhow::Result<()> {
// Check for unsaved changes
if let Some(state) = self
.windows
.get(&self.active_window)
.map(|w| &w.buffers)
.expect("active window present")
.get(&id)
{
if state.buffer.is_modified() {
return Err(anyhow::anyhow!("Buffer has unsaved changes"));
}
}
self.close_buffer_internal(id, false)
}
/// Force close the given buffer without checking for unsaved changes
/// Use this when the user has already confirmed they want to discard changes
pub fn force_close_buffer(&mut self, id: BufferId) -> anyhow::Result<()> {
self.close_buffer_internal(id, false)
}
/// Close the last editor tab while a Utility Dock is present, keeping the
/// editor leaf alive but empty (issue #2283). The editor leaf we intend to
/// keep is made the active split so the synthesized placeholder buffer
/// lands there rather than in the dock, then the closing buffer is torn
/// down with `force_empty_placeholder` so no dock terminal gets adopted.
pub(crate) fn close_tab_keeping_editor_leaf_empty(
&mut self,View on GitHub (pinned to 67894ca546)