sxyazi/yazi · error · io::Error
Not a local URL: {:?}
Error message
Not a local URL: {:?} What it means
`Local::read_dir` (local.rs:104) dispatches on `self.url.kind()`: `Regular` and `Search` are listed via `tokio::fs::read_dir`, but `Mount | Hub | Scope | Sftp` kinds return `InvalidInput` with `Not a local URL: {:?}`. This is reachable because a `Url::Search` can carry a location whose kind is non-local (e.g. a search rooted inside an archive mount), even though `Local::new` accepted it.
Source
Thrown at yazi-fs/src/engine/local/local.rs:104
#[inline]
async fn new<'b>(url: Url<'b>) -> io::Result<Self::Me<'b>> {
match url {
Url::Regular(loc) | Url::Search { loc, .. } => Ok(Self::Me { url, path: loc.as_inner() }),
Url::Mount { .. } | Url::Hub { .. } | Url::Scope { .. } | Url::Sftp { .. } => {
Err(io::Error::new(io::ErrorKind::InvalidInput, format!("Not a local URL: {url:?}")))
}
}
}
#[inline]
async fn read_dir(self) -> io::Result<Self::ReadDir> {
Ok(match self.url.kind() {
AuthKind::Regular => Self::ReadDir::Regular(tokio::fs::read_dir(self.path).await?),
AuthKind::Search => Self::ReadDir::Others {
reader: tokio::fs::read_dir(self.path).await?,
dir: Arc::new(self.url.to_owned()),
},
AuthKind::Mount | AuthKind::Hub | AuthKind::Scope | AuthKind::Sftp => Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("Not a local URL: {:?}", self.url),
))?,
})
}
#[inline]
async fn read_link(&self) -> io::Result<PathBufDyn> {
Ok(tokio::fs::read_link(self.path).await?.into())
}
#[inline]
async fn remove_dir(&self) -> io::Result<()> { tokio::fs::remove_dir(self.path).await }
#[inline]
async fn remove_dir_all(&self) -> io::Result<()> { tokio::fs::remove_dir_all(self.path).await }
#[inline]View on GitHub (pinned to 94abcfa92f)
Solutions
- Before `read_dir`, check `url.kind()` and route non-Regular/Search kinds to the owning backend.
- When creating search URLs over remote/mounted roots, enumerate through that root's engine rather than the local one.
- Log the full URL (`{:?}` of `self.url`) at the failure site to identify which kind leaked through.
Example fix
// before
let entries = local.read_dir().await?; // InvalidInput if kind is Mount/Sftp
// after
use yazi_fs::engine::AuthKind;
match local.url().kind() {
AuthKind::Regular | AuthKind::Search => { let entries = local.read_dir().await?; }
kind => { /* delegate to the engine registered for `kind` */ }
} Defensive patterns
Strategy: validation
Validate before calling
use yazi_fs::engine::AuthKind;
match local.url().kind() {
AuthKind::Regular | AuthKind::Search => { /* safe to read_dir */ }
kind => { /* delegate listing to the engine owning `kind` */ }
} Type guard
fn is_listable_locally(kind: AuthKind) -> bool {
matches!(kind, AuthKind::Regular | AuthKind::Search)
} Try / catch
match local.read_dir().await {
Ok(rd) => { /* ... */ }
Err(e) if e.kind() == io::ErrorKind::InvalidInput => { /* non-local kind leaked in: log url {:?} and re-dispatch */ }
Err(e) => return Err(e),
} Prevention
- Check the URL kind immediately before read_dir, not just at construction time.
- For searches over remote/mounted roots, enumerate through that root's engine.
- Log the offending URL when this fires so the leaking producer can be fixed.
When it happens
Trigger: Constructing `Local` from a `Url::Search` whose underlying location is a mount/hub/sftp URL, then calling `read_dir()`; or re-kindling a URL that changed kind between construction and the `read_dir` call.
Common situations: Searching inside an archived or remote directory and then trying to enumerate the results through the local engine; plugins that rewrap search URLs of remote roots into local handles.
Related errors
AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16).
Data as JSON: /api/errors/ab978e79a03e299c.
Report an issue: GitHub.