denoland/deno · error

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

Error message

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

What it means

The local (LRU) cache directory computes a storage path from a URL the same way the HTTP cache does: it calls base_url_to_filename_parts (libs/cache_dir/common.rs:13), which only accepts http, https, data and blob schemes. When the scheme is anything else the helper returns None and this InvalidInput io::Error is produced with the offending URL. It guards the on-disk layout of the DENO_DIR local cache from URLs it cannot name deterministically.

Source

Thrown at libs/cache_dir/local.rs:688

    } 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 port_separator = "_"; // make this shorter with just an underscore
  let Some(mut base_parts) = base_url_to_filename_parts(url, port_separator)
  else {
    return Err(std::io::Error::new(
      ErrorKind::InvalidInput,
      format!("Can't convert url (\"{}\") to filename.", url),
    ));
  };

  if base_parts[0] == "https" {
    base_parts.remove(0);
  } else {
    let scheme = base_parts.remove(0);
    base_parts[0] = Cow::Owned(format!("{}_{}", scheme, base_parts[0]));
  }

  // first, try to get the filename of the path
  let path_segments = url_path_segments(url);
  let mut parts = base_parts
    .into_iter()
    .chain(path_segments.map(Cow::Borrowed))
    .collect::<Vec<_>>();

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Look at the URL in the message and change the caller to pass an http/https/data/blob URL, which are the only schemes the cache naming supports.
  2. If the resource is genuinely local (file:), bypass this cache API and address it by its real filesystem path instead of a URL.
  3. For custom schemes, hash or encode the URL into your own file name instead of routing it through base_url_to_filename_parts.

Example fix

// before
let file_path = local_lru_cache.get(&Url::parse("asset://logo.png")?)?; // Err: Can't convert url ("asset://logo.png") to filename.

// after
let url = Url::parse("asset://logo.png")?;
if !matches!(url.scheme(), "http" | "https" | "data" | "blob") {
  // handle non-cacheable schemes yourself (e.g. hash the whole URL)
  return Ok(None);
}
let file_path = local_lru_cache.get(&url)?;
Defensive patterns

Strategy: validation

Validate before calling

fn can_local_cache_name(url: &url::Url) -> bool {
  matches!(url.scheme(), "http" | "https" | "data" | "blob")
}

if !can_local_cache_name(&url) {
  return Ok(None); // skip the local cache for unsupported schemes
}

Try / catch

match local_cache.get(&url) {
  Ok(Some(data)) => { /* hit */ }
  Ok(None) => { /* miss */ }
  Err(err) if err.kind() == std::io::ErrorKind::InvalidInput => {
    // unsupported scheme — fall back to a scheme-appropriate path
  }
  Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Using the LocalLruCache (DENO_DIR/local fast cache) API that derives file names from URLs with a non-http/https/data/blob scheme, e.g. caching a "file://…" or custom-protocol resource that the local cache key logic tries to convert via base_url_to_filename_parts.

Common situations: Switching a cache from only-remote to mixed local resources; a module loader or extension feeding vendor/custom scheme URLs into the local cache; refactors that changed which URLs reach the local cache; tests with synthetic schemes.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/a01188c200365d90. Report an issue: GitHub.