helix-editor/helix · error · anyhow::Error

failed to send save event: {}

Error message

failed to send save event: {}

What it means

Editor::save funnels each document's saves through a per-document stream (self.saves). The error fires when .send(stream::once(future)) on that stream returns Err, meaning the receiving end of the save pipeline for that document is already closed. In practice the channel is closed during editor/document teardown, so a save requested in that window fails with "failed to send save event".

Source

Thrown at helix-view/src/editor.rs:2266

        // When a file is written to, notify the file event handler.
        // Note: This can be removed once proper file watching is implemented.
        let handler = self.language_servers.file_event_handler.clone();
        let future = async move {
            let res = doc_save_future.await;
            if let Ok(event) = &res {
                handler.file_changed(event.path.clone());
            }
            res
        };

        use futures_util::stream;

        self.saves
            .get(&doc_id)
            .ok_or_else(|| anyhow::format_err!("saves are closed for this document!"))?
            .send(stream::once(Box::pin(future)))
            .map_err(|err| anyhow!("failed to send save event: {}", err))?;

        self.write_count += 1;

        Ok(())
    }

    pub fn resize(&mut self, area: Rect) {
        if self.tree.resize(area) {
            self._refresh();
        };
    }

    pub fn focus(&mut self, view_id: ViewId) {
        if self.tree.focus == view_id {
            return;
        }

        // Reset mode to normal and ensure any pending changes are committed in the old document.

View on GitHub (pinned to 079a789e8c)

Solutions

  1. Ensure saves are not requested after the document or editor begins closing (check the document is still open / editor not shutting down before calling save).
  2. If it happens on exit with format-on-save or autosave enabled, disable those for the session or update Helix — teardown races here are worth an upstream issue if reproducible.
  3. For embedders, keep the event loop running until all write_count saves settle before dropping the editor.
Defensive patterns

Strategy: try-catch

Validate before calling

if !editor.saves_for_doc_open(doc_id) { // expose/check that the per-doc save stream exists
    return Err(anyhow!("save pipeline already closed for {doc_id:?}"));
}
editor.save(doc_id, /* ... */)?;

Try / catch

if let Err(err) = editor.save(/* ... */) {
    if err.to_string().contains("failed to send save event") {
        // channel closed during teardown: not retryable, surface but do not crash
        log::debug!("save dropped during shutdown: {err:#}");
    } else {
        return Err(err);
    }
}

Prevention

When it happens

Trigger: Issuing a save (including format-on-save or write-then-close sequences) for a document whose save handler has been dropped: saving during editor shutdown, a race between closing a view/document and a pending save, or an embedder calling save after the editor event loop stopped draining saves.

Common situations: Automation or plugins that trigger writes while the editor is exiting; rapid :q with pending autosave/format-on-save; embedders (helix as a library) that shut down the event loop with saves still queued.

Related errors


AI-assisted analysis of helix-editor/helix@079a789e8c (2026-08-16). Data as JSON: /api/errors/c7456ea3dbf7c184. Report an issue: GitHub.