astral-sh/ruff · error
failed to deserialize diagnostic data: {err}
Error message
failed to deserialize diagnostic data: {err} What it means
Ruff's LSP server attaches JSON payload (`data`) to diagnostics it publishes so code actions can map back to the originating lint fix. When a client returns a diagnostic for fix application whose `data` cannot be deserialized into `AssociatedDiagnosticData`, `fixes_for_diagnostics` fails with this anyhow error embedding the serde error.
Source
Thrown at crates/ruff_server/src/lint.rs:305
document: CheckedDocument::Toml(document),
}
}
/// Converts LSP diagnostics to a list of `DiagnosticFix`es by deserializing associated data on each diagnostic.
pub(crate) fn fixes_for_diagnostics(
diagnostics: Vec<lsp_types::Diagnostic>,
) -> crate::Result<Vec<DiagnosticFix>> {
diagnostics
.into_iter()
.filter(|diagnostic| diagnostic.source.as_deref() == Some(DIAGNOSTIC_NAME))
.map(move |mut diagnostic| {
let Some(data) = diagnostic.data.take() else {
return Ok(None);
};
let fixed_diagnostic = diagnostic;
let associated_data: crate::lint::AssociatedDiagnosticData =
serde_json::from_value(data).map_err(|err| {
anyhow::anyhow!("failed to deserialize diagnostic data: {err}")
})?;
Ok(Some(DiagnosticFix {
fixed_diagnostic,
code: associated_data.code,
title: associated_data.title,
noqa_edit: associated_data.noqa_edit,
edits: associated_data.edits,
is_preferred: associated_data.is_preferred,
}))
})
.filter_map(crate::Result::transpose)
.collect()
}
enum CheckedDocument<'a> {
Python {
source: SourceKind,
index: LineIndex,View on GitHub (pinned to 26f38c119c)
Solutions
- Re-trigger diagnostics (save file / restart server) so data is regenerated by the current Ruff version
- Update the Ruff server and client extension together so the AssociatedDiagnosticData schema matches
- Check that no client plugin rewrites or filters the `data` field of Ruff diagnostics
- If persistent, clear cached workspace state in the editor and restart the LSP server
Example fix
// before (client rewrote data)
diagnostic.data = json!({"source": "other"});
// after
// pass the diagnostic through untouched so `data` keeps code/title/noqa_edit
send(diagnostic); Defensive patterns
Strategy: try-catch
Validate before calling
// Client-side validation before sending a fix request
def ruff_diagnostic_data_is_intact(diag):
data = diag.get("data") or {}
return (
isinstance(data.get("code"), (str, int))
and isinstance(data.get("title"), str)
and ("noqa_edit" not in data or isinstance(data["noqa_edit"], dict))
) Try / catch
// Client (TypeScript)
try {
await client.sendRequest('workspace/executeCommand', { command: 'ruff.applyAutofix', arguments: [...] });
} catch (e) {
if (String(e.message).includes('failed to deserialize diagnostic data')) {
await restartRuffServer(); // regenerate diagnostics with current schema
} else throw e;
} Prevention
- Never mutate or strip the `data` field of Ruff diagnostics in client middleware
- Keep the Ruff binary and editor extension versions in sync
- Clear cached/published diagnostics after a server restart
- Filter diagnostics by `source === 'ruff'` before requesting fixes
When it happens
Trigger: Calling a fix code action (e.g. `ruff.applyAutofix` via fixes_for_diagnostics) where a diagnostic's `data` field is missing expected keys (`code`, `title`, `noqa_edit`) or has wrong types — typically because the client modified, cached, filtered, or round-tripped the diagnostic through another server/tool.
Common situations: Editor extensions that copy or transform diagnostics between servers; stale diagnostics from an older Ruff version after upgrade whose data schema changed; clients that serialize/deserialize data lossy (dropping nested objects).
Related errors
- JSON parsing failure: {json_err}
- InternalError
- InternalError
- InvalidParams
- should be set because `extract_if` only yields elements with
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/4db11394110121ac.
Report an issue: GitHub.