astral-sh/ruff · error · std::io::Error
InvalidInput
InvalidInput
Error message
Input is not a text document: {path} What it means
The ty server resolves virtual paths (untitled documents, notebook cells) through the LSP document index. read_virtual_path_to_string looks the path up and requires the stored Document to be a text document; if it is a Notebook document it returns ErrorKind::InvalidInput with 'Input is not a text document: {path}'.
Source
Thrown at crates/ty_server/src/system.rs:340
struct UntrustedWorkspaceExecutor;
impl CommandExecutor for UntrustedWorkspaceExecutor {
fn execute(&self, _command: Command) -> Result<Output> {
Err(std::io::Error::new(
std::io::ErrorKind::PermissionDenied,
"external commands are disabled in an untrusted workspace",
))
}
fn dyn_clone(&self) -> Box<dyn CommandExecutor> {
Box::new(Self)
}
}
fn not_a_text_document(path: impl Display) -> std::io::Error {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Input is not a text document: {path}"),
)
}
fn virtual_path_not_found(path: impl Display) -> std::io::Error {
std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Virtual path does not exist: {path}"),
)
}
/// Helper function to get the [`FileRevision`] of the given document.
fn document_revision(document: &Document, index: &Index) -> FileRevision {
// The file revision is just an opaque number which doesn't have any significant meaning other
// than that the file has changed if the revisions are different.
#[expect(clippy::cast_sign_loss)]
match document {
Document::Text(text) => FileRevision::new(text.version() as u128),
Document::Notebook(notebook) => {View on GitHub (pinned to d1087a4b9e)
Solutions
- Use notebook-aware reads (read_to_notebook) for notebook documents instead of read_to_string
- Inspect the document kind in the index before choosing the read API
- Ensure the client's notebookDocument capabilities match how the documents are actually synced
Defensive patterns
Strategy: validation
Validate before calling
// Before reading a virtual path, confirm the synced document kind matches the read API
let expected_text = matches!(index.document_for(path), Some(Document::Text(_)));
if !expected_text { use_notebook_read_instead(); } Type guard
fn is_text_document(doc: &Document) -> bool { matches!(doc, Document::Text(_)) } Try / catch
match system.read_virtual_path_to_string(path) {
Ok(s) => { /* use s */ }
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => { /* re-read as notebook or skip */ }
Err(e) => return Err(e),
} Prevention
- Keep notebook and text reads paired with the corresponding document kind
- Advertise notebookDocument capabilities consistently in the client
- Log the document kind alongside virtual-path read failures
When it happens
Trigger: A string-oriented read hits a virtual path whose open LSP document is a NotebookDocument instead of a TextDocument - e.g. notebook cell paths read via read_to_string while the editor syncs that document as a notebook.
Common situations: Editors that sync Jupyter files as NotebookDocuments (VS Code Jupyter) while a code path assumes plain text; notebook-document support toggling between ty versions; stale assumptions about how a path is synced.
Related errors
- InternalError
- NotFound
- Server notebook document could not be converted to ty's note
- Notebook document expected from notebook source kind
- Text document URI does not point to a text document
AI-assisted analysis of astral-sh/ruff@d1087a4b9e (2026-08-20).
Data as JSON: /api/errors/c68d1d07071c32ba.
Report an issue: GitHub.