zed-industries/zed · warning · anyhow::Error

Buffer edited while formatting. Aborting

Error message

Buffer edited while formatting. Aborting

What it means

lsp_store applies formatting as one undo transaction: after the first edits establish a text::TransactionId, every follow-up batch goes through extend_formatting_transaction, which requires the buffer's topmost undo transaction to still be that same formatting transaction (crates/project/src/lsp_store.rs:15219). If any other edit landed in between, the ids no longer match and the remaining edits are aborted so stale formatting never clobbers user edits.

Source

Thrown at crates/project/src/lsp_store.rs:16544

    fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
        self.language_registry.update_lsp_binary_status_for_entity(
            self.status_source_id(),
            server_name,
            status,
        );
    }

    fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
        self.language_registry
            .all_lsp_adapters()
            .into_iter()
            .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
            .sorted_by_key(|adapter| adapter.name())
            .collect()
    }

    async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
        let dir = self.language_registry.language_server_download_dir(name)?;

        if !dir.exists() {
            smol::fs::create_dir_all(&dir)
                .await
                .context("failed to create container directory")
                .log_err()?;
        }

        Some(dir)
    }

    async fn read_text_file(&self, path: &RelPath) -> Result<String> {
        let entry = self
            .worktree
            .entry_for_path(path)
            .with_context(|| format!("no worktree entry for path {path:?}"))?;
        let abs_path = self.worktree.absolutize(&entry.path);

View on GitHub (pinned to 9d272b0363)

Solutions

  1. Re-trigger the format/save - the next attempt starts a fresh transaction
  2. Avoid editing while format-on-save is in flight; the abort is by design and harmless
  3. If it recurs constantly, check that two language servers are not both formatting on save, and disable format_on_save for one of them
Defensive patterns

Strategy: retry

Try / catch

match format_buffer(buffer, cx).await {
    Err(e) if e.to_string().contains("Buffer edited while formatting") => {
        // user typed mid-format; re-run once against the now-current buffer
        format_buffer(buffer, cx).await
    }
    other => other,
}

Prevention

When it happens

Trigger: Something edits the buffer between the first formatting edit and a later extend_formatting_transaction call - typically the user typing while format-on-save is still applying LSP edits, or a second language server racing to format the same buffer.

Common situations: Slow language servers returning edits in several responses while the user keeps typing; format-on-save combined with aggressive auto-save; prettier and a linter both configured to format.

Related errors


AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20). Data as JSON: /api/errors/c337654e0e5f3104. Report an issue: GitHub.