{"record":{"id":"bb102877957654b9","repo":"Automattic/harper","slug":"unable-to-convert-url-to-file-path","errorCode":null,"errorMessage":"Unable to convert URL to file path.","messagePattern":"Unable to convert URL to file path\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"harper-ls/src/backend.rs","lineNumber":231,"sourceCode":"    async fn generate_file_dictionary(&self, uri: &Uri) -> Result<MergedDictionary> {\n        let (global_dictionary, file_dictionary) = tokio::join!(\n            self.generate_global_dictionary(),\n            self.load_file_dictionary(uri)\n        );\n\n        let mut global_dictionary =\n            global_dictionary.context(\"Unable to load the user dictionary.\")?;\n        global_dictionary.add_dictionary(Arc::new(\n            file_dictionary.context(\"Unable to load the file dictionary.\")?,\n        ));\n\n        Ok(global_dictionary)\n    }\n\n    async fn update_document_from_file(&self, uri: &Uri, language_id: Option<&str>) -> Result<()> {\n        let content = tokio::fs::read_to_string(\n            uri.to_file_path()\n                .ok_or_else(|| anyhow!(\"Unable to convert URL to file path.\"))?,\n        )\n        .await\n        .with_context(|| format!(\"Unable to read from file {uri:?}\"))?;\n\n        self.update_document(uri, &content, language_id).await\n    }\n\n    async fn update_document(\n        &self,\n        uri: &Uri,\n        text: &str,\n        language_id: Option<&str>,\n    ) -> Result<()> {\n        self.pull_config().await;\n\n        // Copy necessary configuration to avoid holding lock.\n        let (\n            lint_config,","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/Automattic/harper/blob/5fe7d5ab76492d83f3ecdbc3f1da83c75dcb6f83/harper-ls/src/backend.rs#L213-L249","documentation":"`update_document_from_file` converts an LSP document URI to a filesystem path with `uri.to_file_path()`. This returns None for URIs that are not `file://` (e.g. untitled:, remote/virtual schemes), and the code bails with \"Unable to convert URL to file path.\" before attempting the read.","triggerScenarios":"Calling the relopen/execute_command path or did_change_configuration-triggered refresh with a URI like `untitled:Untitled-1`, `remote://...`, `zip://...`, or any non-file scheme; also malformed file URIs without a host/authority that Rust's to_file_path rejects.","commonSituations":"Editor buffers not backed by a file (new unsaved documents), remote-development (SSH/WSL/container) virtual filesystems, or extensions that expose documents through custom schemes.","solutions":["Save the buffer so it has a real file:// URI before triggering the reload.","Skip/ignore the update for non-file schemes; only pass file:// URIs to this path.","For remote development, ensure harper-ls runs on the same host as the files so file:// URIs resolve.","Percent-encode the URI properly; malformed file URIs (bad authority) also fail to_file_path."],"exampleFix":"// before (client sends)\nuntitled:Untitled-1\n// after\n// save the document first so the URI becomes\nfile:///home/user/project/Untitled-1.ts","handlingStrategy":"type-guard","validationCode":"function isFileUri(uri) {\n  try { const u = new URL(uri); return u.protocol === 'file:'; } catch { return false; }\n}","typeGuard":"function canConvertToFilePath(uri) {\n  return uri.startsWith('file://') && !uri.startsWith('file://'); // no-op guard placeholder\n}","tryCatchPattern":"try {\n  await reloadDocument(uri);\n} catch (err) {\n  if (String(err.message).includes('Unable to convert URL to file path')) {\n    // non-file or malformed URI; save the buffer or skip virtual documents\n  }\n}","preventionTips":["Save unsaved buffers before triggering reload commands","Filter out non-file schemes (untitled:, remote:, custom) before sending to harper-ls","Run the language server on the same host/filesystem as the documents","Percent-encode file URIs correctly"],"tags":["lsp","uri","filesystem","rust"],"backgroundTag":"invalid-url-format","analyzedSha":"5fe7d5ab76492d83f3ecdbc3f1da83c75dcb6f83","analyzedAt":"2026-09-06T11:34:38.610Z","contentChangedAt":"2026-09-06T11:34:38.610Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}