denoland/deno · error · std::io::Error

InvalidInput

InvalidInput

Error message

Can't convert url ("{}") to filename.

What it means

libs/cache_dir's url_to_filename converts a remote-module URL into a cache file path by deriving parts from the URL's origin via base_url_to_filename_parts. URLs whose scheme/shape cannot be represented as cache paths (unsupported scheme, no host, etc.) yield None and this InvalidInput error, since the URL cannot map to a filesystem location.

Source

Thrown at libs/cache_dir/cache.rs:99

        actual,
      }))
    } else {
      Ok(())
    }
  }
}

/// Turn provided `url` into a hashed filename.
/// URLs can contain a lot of characters that cannot be used
/// in filenames (like "?", "#", ":"), so in order to cache
/// them properly they are deterministically hashed into ASCII
/// strings.
pub fn url_to_filename(url: &Url) -> std::io::Result<PathBuf> {
  // Replaces port part with a special string token (because
  // ":" cannot be used in filename on some platforms).
  // Ex: $DENO_DIR/remote/https/deno.land/
  let Some(cache_parts) = base_url_to_filename_parts(url) else {
    return Err(std::io::Error::new(
      ErrorKind::InvalidInput,
      format!("Can't convert url (\"{}\") to filename.", url),
    ));
  };

  let rest_str = if let Some(query) = url.query() {
    let mut rest_str =
      String::with_capacity(url.path().len() + 1 + query.len());
    rest_str.push_str(url.path());
    rest_str.push('?');
    rest_str.push_str(query);
    Cow::Owned(rest_str)
  } else {
    Cow::Borrowed(url.path())
  };

  // NOTE: fragment is omitted on purpose - it's not taken into
  // account when caching - it denotes parts of webpage, which

View on GitHub (pinned to 336da420f4)

Solutions

  1. Only pass remote http/https URLs to cache-path APIs; handle file:/blob: URLs with local-path logic instead.
  2. Validate the URL scheme and host before requesting a cache filename.
  3. Fix malformed/dynamically built URLs (missing host, wrong scheme).
  4. Catch std::io::Error with ErrorKind::InvalidInput and fall back to a non-cache path.

Example fix

// before
let path = get_cache_filename(&Url::parse("file:///local/mod.ts")?).unwrap();
// after
let url = Url::parse("https://deno.land/x/mod.ts")?;
if url.scheme().starts_with("http") {
  let path = get_cache_filename(&url)?;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isCacheable(u: URL): boolean {
  return (u.protocol === "https:" || u.protocol === "http:") && u.hostname !== "";
}

Type guard

function isRemoteHttpUrl(u: URL): u is URL {
  return /^https?:$/.test(u.protocol) && u.hostname.length > 0;
}

Try / catch

try {
  const path = get_cache_filename(url);
} catch (e) {
  if (e instanceof Deno.errors.InvalidData || e.code === "InvalidInput") {
    // non-cacheable URL: skip caching or handle via local loader
  } else throw e;
}

Prevention

When it happens

Trigger: Calling local_path_for_url/get_cache_filename with a URL that has no base-encodable parts — e.g. non-http(s)/data-unsupported schemes (file:, blob:, custom schemes), URLs without a host, or malformed URLs accepted by the Url parser but not cacheable.

Common situations: Caching code fed blob: or file: URLs; tests passing synthetic URLs; custom loaders emitting non-remote URLs into the HTTP cache path; typos like htp:// in dynamically constructed 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


AI-assisted analysis of denoland/deno@336da420f4 (2026-09-11). Data as JSON: /api/errors/7178eff668b1f411. Report an issue: GitHub.