denoland/deno · error · std::io::Error
InvalidInput
InvalidInput
Error message
Can't convert url ("{}") to filename. What it means
url_to_local_sub_path builds the local (on-disk) sub-path for a cached remote module in the newer cache layout, using base_url_to_local_filename_part. If the URL's base cannot be converted (unsupported scheme/host shape, or path segments that are forbidden Windows names, empty, or end with '.'), this InvalidInput error is thrown because no safe local path can be derived. It is raised through the Cache API surface (get/set/local_path_for_url/etc.).
Source
Thrown at libs/cache_dir/local.rs:697
// prevent collisions with a directory of the same name
!has_known_extension(part) || !part.ends_with(last_ext)
} else {
// if any non-ending path part has a known extension, hash it in order to
// prevent collisions where a filename has the same name as a directory name
has_known_extension(part)
};
// the hash symbol at the start designates a hash for the url part
hash_context_specific
|| part.starts_with('#')
|| has_forbidden_chars(part)
|| last_ext.is_none() && FORBIDDEN_WINDOWS_NAMES.contains(part)
|| part.ends_with('.')
}
// get the base url
let Some(base_part) = base_url_to_local_filename_part(url) else {
return Err(std::io::Error::new(
ErrorKind::InvalidInput,
format!("Can't convert url (\"{}\") to filename.", url),
));
};
// first, try to get the filename of the path
let path_segments = url_path_segments(url);
let mut parts = std::iter::once(base_part)
.chain(path_segments.map(Cow::Borrowed))
.collect::<Vec<_>>();
// push the query parameter onto the last part
if let Some(query) = url.query() {
let last_part = parts.last_mut().unwrap();
let last_part = match last_part {
Cow::Borrowed(_) => {
*last_part = Cow::Owned(last_part.to_string());
match last_part {View on GitHub (pinned to 336da420f4)
Solutions
- Ensure only http/https URLs are written into the remote cache; route data:/file: URLs to a different loader path.
- Sanitize or rename URL path segments that collide with forbidden Windows names (CON, PRN, AUX, NUL, COM1-9, LPT1-9) or end with '.'.
- Validate the URL (scheme + host present) before calling cache APIs.
- Catch the InvalidInput io::Error and treat the URL as non-cacheable rather than unwrapping.
Example fix
// before
cache.set(&Url::parse("https://host/CON")?, headers, bytes)?; // forbidden Windows name
// after
let url = Url::parse("https://host/const_js")?; // sanitized segment
if url.scheme().starts_with("http") {
cache.set(&url, headers, bytes)?;
} Defensive patterns
Strategy: validation
Validate before calling
const FORBIDDEN = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|$)/i;
function isLocalCacheSafe(u: URL): boolean {
return /^https?:$/.test(u.protocol) && u.hostname !== "" &&
u.pathname.split("/").every(seg => seg !== "" && !seg.endsWith(".") && !FORBIDDEN.test(seg));
} Type guard
function isHttpUrlWithSafeSegments(u: URL): u is URL {
return (u.protocol === "http:" || u.protocol === "https:") &&
!u.pathname.split("/").some(s => s === "" || s.endsWith("."));
} Try / catch
try {
cache.set(url, headers, body);
} catch (e) {
if (e instanceof Deno.errors.InvalidData || e.code === "InvalidInput") {
console.warn(`skipping non-cacheable url: ${url}`);
} else throw e;
} Prevention
- Only insert http/https URLs into the remote HTTP cache.
- Sanitize path segments for Windows reserved names and trailing dots.
- Don't feed data: URLs from custom loaders into the disk cache.
- Treat this error as 'URL not cacheable' and skip rather than crash.
When it happens
Trigger: Calling HttpCache set/get/read_modified_time/get_file_url/local_path_for_url with a URL whose scheme isn't http/https or whose host/segments fail sanitization — e.g. "data:text/javascript,...", hostless URLs, or path segments named like CON/NUL or ending in a dot on Windows.
Common situations: Custom loaders injecting data: URLs into the HTTP cache; redirected URLs with odd segments; Windows-reserved filenames coming from remote servers; corrupted redirect chains storing non-remote URLs.
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
- failed to atomic-rename LAUFEY cache to {}: {e}
- InvalidInput
- Can't convert url ("{}") to filename.
- Can't convert url ("{}") to filename.
- ERR_FS_INVALID_SYMLINK_TYPE
AI-assisted analysis of denoland/deno@336da420f4 (2026-09-11).
Data as JSON: /api/errors/eb4ca816621254ad.
Report an issue: GitHub.