sinelaw/fresh · error
URI is not a file path (container-side decode failed)
Error message
URI is not a file path (container-side decode failed)
What it means
In open_lsp_uri_target's container branch (a translation/authority is active), the code decodes the URI's raw path verbatim to run `cat <path>` inside the container. If uri.to_host_path(None) returns None — the URI has no decodable file path — this error is thrown before any container command runs.
Solutions
- Log and inspect the incoming LspUri; confirm it is a file:// URI with a non-empty path
- Handle virtual-document schemes separately instead of treating them as container paths
- Check the LSP server version/config for options that emit plain file paths
- Fall back to Case 1 (host path) semantics or surface a friendly message when the URI is not a file
Example fix
// before
let container_path = uri.to_host_path(None).ok_or_else(|| {
anyhow::anyhow!("URI is not a file path (container-side decode failed)")
})?;
// after
let Some(container_path) = uri.to_host_path(None) else {
log::warn!("skipping non-file LSP URI: {}", uri.as_str());
return Ok(self.active_buffer_id());
}; Defensive patterns
Strategy: validation
Validate before calling
if translation.is_some() && uri.to_host_path(None).is_none() {
// skip container fetch, show message instead
} Type guard
fn container_path_of(uri: &LspUri) -> Option<std::path::PathBuf> {
uri.to_host_path(None)
} Try / catch
match self.open_lsp_uri_target(&uri) {
Err(e) if e.to_string().contains("container-side decode failed") => {
log::warn!("cannot fetch non-file URI from container: {}", uri.as_str());
}
other => other?,
} Prevention
- Decode the URI path with to_host_path(None) before entering the container branch
- Reject virtual-document schemes early in the goto-definition handler
- Test container-mode goto-definition with servers known to emit non-file URIs
- Keep container fetch behind a capability check so invalid URIs degrade gracefully
When it happens
Trigger: goto-definition returns a non-file:// or malformed URI while the editor is attached to a devcontainer/remote authority, so the container-side decode of the URI path fails.
Common situations: Remote development against a language server that reports definitions with virtual or custom URI schemes; a corrupt URI produced by a buggy server over the wire.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- URI is not a file path
- could not open : file not found
- could not open : no tokio runtime available for container…
- Buffer not found
- active window present
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/95dc79f958f06a14.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/app/file_open_orchestrators.rs:708
// `open_file` focuses, which is what callers (goto-def,
// workspace edits) expect — they want the cursor to land in
// the destination buffer afterward.
if self.authority().filesystem.exists(&host_path) {
return self.open_file(&host_path);
}
// Case 2: container-only fetch. Only meaningful when the
// active authority can route a `cat` through to the
// container — `path_translation` being set is the proxy for
// "this is a container authority". Local + SSH authorities
// skip straight to the error case.
if translation.is_some() {
// The container-side path is the URI's raw path. Calling
// `to_host_path` with `None` returns the wire-side path
// verbatim (no translation applied) — exactly what we
// need for `cat <path>` inside the container.
let container_path = uri.to_host_path(None).ok_or_else(|| {
anyhow::anyhow!("URI is not a file path (container-side decode failed)")
})?;
let buffer_id = self.fetch_and_open_container_file(container_path, uri.clone())?;
// Match `open_file`'s focus behaviour so the cursor
// assertion in callers (goto-def's `MoveCursor` event)
// applies to the right buffer.
self.set_active_buffer(buffer_id);
return Ok(buffer_id);
}
// Case 3: nothing we can open.
Err(anyhow::anyhow!(
"could not open {}: file not found",
host_path.display()
))
}
/// Run `cat <container_path>` through the active authority's
/// process spawner and open the result as a read-only bufferView on GitHub (pinned to 67894ca546)