{"record":{"id":"a7b8f683242c7521","repo":"astral-sh/ruff","slug":"notfound-a7b8f6","errorCode":"NotFound","errorMessage":"Virtual path does not exist: {path}","messagePattern":"Virtual path does not exist: (.+?)","errorType":"error_code","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/ty_server/src/system.rs","lineNumber":347,"sourceCode":"        ))\n    }\n\n    fn dyn_clone(&self) -> Box<dyn CommandExecutor> {\n        Box::new(Self)\n    }\n}\n\nfn not_a_text_document(path: impl Display) -> std::io::Error {\n    std::io::Error::new(\n        std::io::ErrorKind::InvalidInput,\n        format!(\"Input is not a text document: {path}\"),\n    )\n}\n\nfn virtual_path_not_found(path: impl Display) -> std::io::Error {\n    std::io::Error::new(\n        std::io::ErrorKind::NotFound,\n        format!(\"Virtual path does not exist: {path}\"),\n    )\n}\n\n/// Helper function to get the [`FileRevision`] of the given document.\nfn document_revision(document: &Document, index: &Index) -> FileRevision {\n    // The file revision is just an opaque number which doesn't have any significant meaning other\n    // than that the file has changed if the revisions are different.\n    #[expect(clippy::cast_sign_loss)]\n    match document {\n        Document::Text(text) => FileRevision::new(text.version() as u128),\n        Document::Notebook(notebook) => {\n            // VS Code doesn't always bump the notebook version when the cell content changes.\n            // Specifically, I noticed that VS Code re-uses the same version when:\n            // 1. Adding a new cell\n            // 2. Pasting some code that has an error\n            //\n            // The notification updating the cell content on paste re-used the same version as when the cell was added.\n            // Because of that, hash all cell versions and the notebook versions together.","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/astral-sh/ruff/blob/d1087a4b9e03d253a88703f34e0869ee4b805456/crates/ty_server/src/system.rs#L329-L365","documentation":"Virtual paths only exist while their document is open in the LSP index. read_virtual_path_to_string/read_virtual_path_to_notebook call system_virtual_path_to_document and, when no open document matches, return ErrorKind::NotFound with 'Virtual path does not exist: {path}'.","triggerScenarios":"ty reads a virtual path (untitled file, notebook cell) after the client sent didClose, before the first didOpen, or for a document that was never synced by this client.","commonSituations":"In-flight requests racing a document close (hover finishing after close); editors that skip syncing untitled files; retries against a restarted server holding stale paths.","solutions":["Ensure textDocument/didOpen (or notebook document sync) completes before issuing requests that touch the document","Cancel or discard work for documents that receive didClose","Validate the virtual path against the open-document index before reading"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Issue requests only while the document is open\nif (!openDocuments.has(virtualPath)) {\n  await connection.sendRequest('textDocument/didOpen' /* ensure open first */);\n}","typeGuard":null,"tryCatchPattern":"match system.read_virtual_path_to_string(path) {\n    Ok(text) => { /* use text */ }\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => { /* document closed: drop the stale work item */ }\n    Err(e) => return Err(e),\n}","preventionTips":["Send didOpen before any feature request touching a document","Cancel in-flight work on didClose","Never cache virtual paths across server restarts"],"tags":["lsp","virtual-path","file-not-found","document-sync"],"backgroundTag":"file-not-found","analyzedSha":"d1087a4b9e03d253a88703f34e0869ee4b805456","analyzedAt":"2026-08-20T16:33:49.445Z","contentChangedAt":"2026-08-20T16:33:49.445Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}