astral-sh/ruff · error
InternalError
InternalError
Error message
Notebook document expected from notebook source kind
What it means
An InternalError from the ruff language server's fix pipeline: the document being fixed was classified as an ipynb notebook (source kind and transformed content both parsed as notebooks), but the session's stored query document could not be retrieved as a notebook. This is a broken internal invariant between the source-kind detection and the session document index, not a user configuration issue.
Solutions
- Restart the ruff language server / reload the editor window to rebuild the document index
- Update the ruff VS Code extension (and bundled server) — state-desync bugs in the notebook fix path get fixed over time
- If reproducible, capture the editor logs and file an issue at https://github.com/astral-sh/ruff/issues with the notebook and steps
Defensive patterns
Strategy: fallback
Prevention
- Keep the ruff server and editor extension on matching, current versions
- After rapid notebook cell open/close churn, restart the server if fixes start failing
- Capture editor LSP logs when it reproduces so the state mismatch can be reported precisely
When it happens
Trigger: Applying a code action / auto-fix on a .ipynb notebook open in the editor when the server's document index holds a stale or mismatched entry for that URI; typically after notebook cells were opened/closed rapidly or the server state desynchronized.
Common situations: Editor extension races during notebook editing; server restarted mid-session while notebook documents remained open; version skew between editor extension and ruff server.
Related errors
AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20).
Data as JSON: /api/errors/3af3b6e3dd35bf23.
Report an issue: GitHub.
Appendix: source
Thrown at crates/ruff_server/src/fix.rs:107
}
// fast path: if `transformed` is still borrowed, no changes were made and we can return early
if let Cow::Borrowed(_) = transformed {
return Ok(Fixes::default());
}
if let (Some(source_notebook), Some(modified_notebook)) =
(source_kind.as_ipy_notebook(), transformed.as_ipy_notebook())
{
fn cell_source(cell: &ruff_notebook::Cell) -> String {
match cell.source() {
SourceValue::String(string) => string.clone(),
SourceValue::StringArray(array) => array.join(""),
}
}
let Some(notebook) = query.as_notebook() else {
anyhow::bail!("Notebook document expected from notebook source kind");
};
let mut fixes = Fixes::default();
for ((source, modified), uri) in source_notebook
.cells()
.iter()
.map(cell_source)
.zip(modified_notebook.cells().iter().map(cell_source))
.zip(notebook.uris())
{
let source_index = LineIndex::from_source_text(&source);
let modified_index = LineIndex::from_source_text(&modified);
let Replacement {
source_range,
modified_range,
} = Replacement::between(
&source,
source_index.line_starts(),View on GitHub (pinned to d1087a4b9e)