{"record":{"id":"f1f8e7fe025b9800","repo":"sxyazi/yazi","slug":"not-a-local-url-url","errorCode":null,"errorMessage":"Not a local URL: {url:?}","messagePattern":"Not a local URL: (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/engine/local/demand.rs","lineNumber":44,"sourceCode":"\tfn create(&mut self, create: bool) -> &mut Self {\n\t\tself.0.create(create);\n\t\tself\n\t}\n\n\tfn create_new(&mut self, create_new: bool) -> &mut Self {\n\t\tself.0.create_new(create_new);\n\t\tself\n\t}\n\n\tasync fn open<U>(&self, url: U) -> io::Result<Self::File>\n\twhere\n\t\tU: AsUrl,\n\t{\n\t\tlet url = url.as_url();\n\t\tif let Some(path) = url.as_local() {\n\t\t\tself.0.open(path).await\n\t\t} else {\n\t\t\tErr(io::Error::new(io::ErrorKind::InvalidInput, format!(\"Not a local URL: {url:?}\")))\n\t\t}\n\t}\n\n\tfn read(&mut self, read: bool) -> &mut Self {\n\t\tself.0.read(read);\n\t\tself\n\t}\n\n\tfn truncate(&mut self, truncate: bool) -> &mut Self {\n\t\tself.0.truncate(truncate);\n\t\tself\n\t}\n\n\tfn write(&mut self, write: bool) -> &mut Self {\n\t\tself.0.write(write);\n\t\tself\n\t}\n}","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/engine/local/demand.rs#L26-L62","documentation":"The local filesystem engine's `open()` (yazi-fs `Opener` impl in demand.rs) only opens URLs that resolve to a local path. It calls `url.as_url().as_local()`, and when that returns None — i.e. the URL is a `Mount`, `Hub`, `Scope`, or `Sftp` URL rather than a `Regular`/`Search` one — it fails with `io::ErrorKind::InvalidInput`. This is a type-dispatch guard: the local engine refuses URLs that belong to remote/virtual backends.","triggerScenarios":"Calling `open(url)` (or any higher-level API that routes through the local engine, e.g. previewing or reading a file) with a URL string like `sftp://host/file`, an archive-mounted URL (`mount://...`), a hub URL, or a scope URL. Any `AsUrl` value whose `as_url().as_local()` is None triggers it.","commonSituations":"Passing a full URL where a plain filesystem path is expected; plugins constructing URLs from hovered entries inside archives or remote mounts and handing them to file APIs backed by the local engine; hardcoding `search://` or `hub://` strings in scripts.","solutions":["Convert the URL to a local path before opening: only call the local engine when `url.as_local()` is `Some(path)`.","Dispatch by URL kind: route `Sftp`/`Mount`/`Hub`/`Scope` URLs to the engine/backend that owns that kind.","If you actually want the file body of an archived/remote item, use the backend-specific fetch/read API for that URL kind instead of the local opener."],"exampleFix":"// before\nlet file = engine.open(url).await?; // panics path: InvalidInput for sftp:// URLs\n\n// after\nif let Some(path) = url.as_url().as_local() {\n    let file = engine.open(path).await?;\n} else {\n    // route to the remote/mount backend for this URL kind\n}","handlingStrategy":"type-guard","validationCode":"use yazi_shared::url::Url;\n\nfn local_path_of<U: AsUrl>(url: U) -> Option<std::path::PathBuf> {\n    url.as_url().as_local().map(|p| p.to_path_buf())\n}\n\n// before opening:\nlet Some(path) = local_path_of(&url) else {\n    // route to the engine for Sftp/Mount/Hub/Scope\n    return Ok(());\n};","typeGuard":"fn is_local_url(url: &Url) -> bool {\n    url.as_local().is_some()\n}","tryCatchPattern":"match engine.open(url).await {\n    Ok(f) => { /* ... */ }\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput => {\n        // URL was not local; dispatch to the proper backend\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never hand raw URL strings to local-engine APIs; pass them through the URL dispatcher that already switches on URL kind.","Centralize 'is this URL local?' checks in one helper used by every call site.","In tests, include a non-local URL case to catch dispatch regressions early."],"tags":["url","filesystem","io","input-validation","local-engine"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}