{"record":{"id":"e12dddd47523d2e2","repo":"sinelaw/fresh","slug":"uri-is-not-a-file-path","errorCode":null,"errorMessage":"URI is not a file path","messagePattern":"URI is not a file path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/app/file_open_orchestrators.rs","lineNumber":686,"sourceCode":"    ///     `~/.local/.../site-packages/flask/app.py`): fetch the file\n    ///     bytes via the authority's process spawner\n    ///     (`docker exec <id> cat <path>`) and open them as a\n    ///     read-only buffer at the in-container path.\n    ///   * **unreachable** (no file at the host path; container fetch\n    ///     failed or no container authority): return `Err` so the\n    ///     caller can surface a user-visible status message instead\n    ///     of silently opening a phantom buffer.\n    ///\n    /// Cursor placement, focus, and any post-open hook firing are the\n    /// caller's job (this method just resolves \"URI → BufferId\").\n    pub(crate) fn open_lsp_uri_target(\n        &mut self,\n        uri: &crate::app::types::LspUri,\n    ) -> anyhow::Result<BufferId> {\n        let translation = self.authority().path_translation.clone();\n        let host_path = uri\n            .to_host_path(translation.as_ref())\n            .ok_or_else(|| anyhow::anyhow!(\"URI is not a file path\"))?;\n\n        // Case 1: file is reachable on the host filesystem (either\n        // local authority, or workspace-mounted on a devcontainer).\n        // `open_file` focuses, which is what callers (goto-def,\n        // workspace edits) expect — they want the cursor to land in\n        // the destination buffer afterward.\n        if self.authority().filesystem.exists(&host_path) {\n            return self.open_file(&host_path);\n        }\n\n        // Case 2: container-only fetch. Only meaningful when the\n        // active authority can route a `cat` through to the\n        // container — `path_translation` being set is the proxy for\n        // \"this is a container authority\". Local + SSH authorities\n        // skip straight to the error case.\n        if translation.is_some() {\n            // The container-side path is the URI's raw path. Calling\n            // `to_host_path` with `None` returns the wire-side path","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/app/file_open_orchestrators.rs#L668-L704","documentation":"open_lsp_uri_target converts an LSP document URI (e.g. file:///src/main.rs) into a host-filesystem path via LspUri::to_host_path, applying the active authority's path translation (local or devcontainer). When the URI cannot be decoded into a file path (wrong scheme like untitled: or a malformed URI), to_host_path returns None and this anyhow error is thrown instead of opening a buffer.","triggerScenarios":"A goto-definition response from the LSP server returns a URI whose scheme is not file:// (e.g. untitled:, jdt://, or an opaque URI), or a file:// URI whose path component is empty/malformed so to_host_path yields None.","commonSituations":"Language servers that report definitions in virtual documents (Java's jdt://, Rust-analyzer's occasionally synthesized URIs); a misconfigured server returning non-file URIs; LSP servers from other tools sending custom schemes the editor doesn't map.","solutions":["Check what URI the LSP server returned (log the LspUri before calling open_lsp_uri_target) and confirm it uses the file:// scheme","If the server emits virtual-document schemes, add a handler for that scheme instead of routing through open_lsp_uri_target","Verify the authority's path_translation config is intact; a broken translation table can make decoding fail","Reject non-file URIs early in handle_goto_definition_response with a user-facing message instead of a hard error"],"exampleFix":"// before\nlet buffer_id = self.open_lsp_uri_target(&uri)?;\n// after\nif uri.to_host_path(self.authority().path_translation.as_ref()).is_none() {\n    log::warn!(\"goto-def returned non-file URI: {}\", uri.as_str());\n    return Ok(());\n}\nlet buffer_id = self.open_lsp_uri_target(&uri)?;","handlingStrategy":"validation","validationCode":"fn is_file_uri(uri: &LspUri, translation: Option<&PathTranslation>) -> bool {\n    uri.to_host_path(translation).is_some()\n}\n// call open_lsp_uri_target only if is_file_uri(...)","typeGuard":"fn as_host_path<'a>(uri: &'a LspUri, t: Option<&PathTranslation>) -> Option<PathBuf> {\n    uri.to_host_path(t)\n}","tryCatchPattern":"match self.open_lsp_uri_target(&uri) {\n    Ok(id) => /* focus buffer id */,\n    Err(e) if e.to_string().contains(\"URI is not a file path\") => log::warn!(\"non-file LSP URI skipped\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Always check to_host_path for None before requesting a buffer open for an LSP URI","Log incoming goto-definition URIs during language-server integration testing","Treat non-file:// schemes (untitled:, jdt:) as separate features with dedicated handlers","Keep the authority's path_translation table validated at startup"],"tags":["lsp","uri","goto-definition"],"backgroundTag":"invalid-url-format","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}