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
- Re-trigger the format/save - the next attempt starts a fresh transaction
- Avoid editing while format-on-save is in flight; the abort is by design and harmless
- 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
- Treat this abort as a signal to retry, not a bug to fix
- Configure exactly one formatter per buffer to avoid racing transactions
- Debounce format-on-save so edits and format requests rarely interleave
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
- unknown SWE-Atlas part '{part}' (valid: {valid})
- Default prettier is not installed and cannot be started
- Cannot start default prettier due to its installation failur
- incorrect proto inlay hint message: no resolve state in hint
- failed to deserialize response
AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20).
Data as JSON: /api/errors/c337654e0e5f3104.
Report an issue: GitHub.