astral-sh/ruff · error
Failed to read notebook file `{}`: {:?}
Error message
Failed to read notebook file `{}`: {:?} What it means
`ruff_notebook::round_trip` runs Jupyter notebook round-trip source generation on a file path. If the notebook cannot be loaded from disk (missing file, parse error, schema failure), the underlying Notebook::from_path error is wrapped with the path and error detail into this anyhow error.
Source
Thrown at crates/ruff_notebook/src/notebook.rs:25
use std::io;
use std::io::{BufReader, Cursor, Read, Seek, SeekFrom, Write};
use std::path::Path;
use std::sync::OnceLock;
use thiserror::Error;
use ruff_diagnostics::{SourceMap, SourceMarker};
use ruff_source_file::{OneIndexed, UniversalNewlineIterator};
use ruff_text_size::{TextRange, TextSize};
use crate::cell::CellOffsets;
use crate::index::NotebookIndex;
use crate::schema::{Cell, RawNotebook, SortAlphabetically, SourceValue};
use crate::{CellMetadata, CellStart, RawNotebookMetadata, SYNTHETIC_CELL_SEPARATOR, schema};
/// Run round-trip source code generation on a given Jupyter notebook file path.
pub fn round_trip(path: &Path) -> anyhow::Result<String> {
let mut notebook = Notebook::from_path(path).map_err(|err| {
anyhow::anyhow!(
"Failed to read notebook file `{}`: {:?}",
path.display(),
err
)
})?;
let code = notebook.source_code().to_string();
let needs_rebuild = notebook.update_cell_content(&code);
debug_assert!(
!needs_rebuild,
"round-tripping unchanged source cannot remove a synthetic cell separator"
);
let mut writer = Vec::new();
notebook.write(&mut writer)?;
Ok(String::from_utf8(writer)?)
}
/// An error that can occur while deserializing a Jupyter Notebook.
#[derive(Error, Debug)]View on GitHub (pinned to 26f38c119c)
Solutions
- Verify the path exists and is readable (`ls -l`, check permissions)
- Validate the notebook JSON (e.g. `jq . notebook.ipynb` or jupyter's nbformat validate) and fix or regenerate the file
- Re-run after the notebook is saved/closed to rule out a concurrent-writer partial file
- If the file is intentionally not a notebook, remove it from the lint/format target list
Example fix
// before
let code = round_trip(Path::new("outdated_notebook.ipynb"))?;
// after
let path = Path::new("analysis.ipynb");
assert!(path.exists(), "notebook missing: {}", path.display());
let code = round_trip(path)?; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust-side pre-checks before round_trip
use std::path::Path;
fn notebook_readable(path: &Path) -> bool {
path.is_file()
&& std::fs::File::open(path)
.map(|mut f| {
use std::io::Read;
let mut buf = String::new();
f.read_to_string(&mut buf).is_ok()
&& serde_json::from_str::<serde_json::Value>(&buf).is_ok()
})
.unwrap_or(false)
} Try / catch
// Rust
match ruff_notebook::round_trip(path) {
Ok(code) => process(code),
Err(e) if e.to_string().contains("Failed to read notebook file") => {
eprintln!("skipping notebook {path:?}: {e:#}");
}
Err(e) => return Err(e),
} Prevention
- Check path existence and permissions before invoking round_trip
- Validate .ipynb files with nbformat/jq in CI before linting them
- Exclude non-notebook files from notebook-aware lint/format globs
- Regenerate notebooks that fail JSON validation instead of editing them in place
When it happens
Trigger: Calling `ruff_notebook::round_trip(path)` where `path` does not exist, is not readable, or contains a malformed/invalid `.ipynb` JSON document.
Common situations: Typo'd or stale notebook path passed to `ruff check --fix` on notebooks; notebooks produced by tools emitting non-conforming JSON; files deleted or moved between discovery and processing; permission problems in CI containers.
Related errors
- Server notebook document could not be converted to ty's note
- Notebook document path does not point to a notebook document
- extra use-def data should have been retained
- InternalError
- InvalidInput
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/43c91e9330a63679.
Report an issue: GitHub.