{"record":{"id":"fd4daa57a53ed9a6","repo":"denoland/deno","slug":"can-t-convert-url-to-filename","errorCode":null,"errorMessage":"Can't convert url (\"{}\") to filename.","messagePattern":"Can't convert url \\(\"(.+?)\"\\) to filename\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/cache_dir/cache.rs","lineNumber":99,"sourceCode":"        actual,\n      }))\n    } else {\n      Ok(())\n    }\n  }\n}\n\n/// Turn provided `url` into a hashed filename.\n/// URLs can contain a lot of characters that cannot be used\n/// in filenames (like \"?\", \"#\", \":\"), so in order to cache\n/// them properly they are deterministically hashed into ASCII\n/// strings.\npub fn url_to_filename(url: &Url) -> std::io::Result<PathBuf> {\n  // Replaces port part with a special string token (because\n  // \":\" cannot be used in filename on some platforms).\n  // Ex: $DENO_DIR/remote/https/deno.land/\n  let Some(cache_parts) = base_url_to_filename_parts(url, \"_PORT\") else {\n    return Err(std::io::Error::new(\n      ErrorKind::InvalidInput,\n      format!(\"Can't convert url (\\\"{}\\\") to filename.\", url),\n    ));\n  };\n\n  let rest_str = if let Some(query) = url.query() {\n    let mut rest_str =\n      String::with_capacity(url.path().len() + 1 + query.len());\n    rest_str.push_str(url.path());\n    rest_str.push('?');\n    rest_str.push_str(query);\n    Cow::Owned(rest_str)\n  } else {\n    Cow::Borrowed(url.path())\n  };\n\n  // NOTE: fragment is omitted on purpose - it's not taken into\n  // account when caching - it denotes parts of webpage, which","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/libs/cache_dir/cache.rs#L81-L117","documentation":"url_to_filename() maps a Url to a cache filename by first splitting it into [scheme, host] parts via base_url_to_filename_parts (libs/cache_dir/common.rs:13). That helper only understands the http, https, data and blob schemes; every other scheme logs \"Don't know how to create cache name for scheme\" and returns None, which url_to_filename converts into this InvalidInput io::Error echoing the offending URL. It exists because arbitrary schemes (file:, npm:, custom protocols) cannot be mapped deterministically into the cache layout this library maintains.","triggerScenarios":"Calling url_to_filename() directly, or indirectly through HttpCache operations (get/put/remove with cache keys built from URLs), with a URL whose scheme is not http/https/data/blob — e.g. Url::parse(\"file:///mod.ts\"), \"npm:pkg\", \"node:fs\", or a custom protocol URL.","commonSituations":"Custom module loaders that produce non-HTTP specifiers and feed them into the HTTP cache; passing a file path or package specifier where a remote URL is required; newer code paths routing URLs of previously-unseen schemes into the cache; tests using example/spec URLs like \"example:foo\".","solutions":["Inspect the URL printed in the message and fix the caller to pass an http/https (or data/blob) URL — this is almost always a caller bug, not a cache bug.","If you must handle other schemes, branch on url.scheme() before calling url_to_filename and build your own filename for the unsupported schemes instead of relying on the cache layout.","Check where the URL originates (module loader, CLI arg, config file) and make sure a file path or bare specifier was not coerced into a Url with an unexpected scheme."],"exampleFix":"// before\nlet path = url_to_filename(&Url::parse(\"file:///mod.ts\")?)?; // Err: Can't convert url (\"file:///mod.ts\") to filename.\n\n// after\nlet url = Url::parse(\"file:///mod.ts\")?;\nlet path = match url.scheme() {\n  \"http\" | \"https\" | \"data\" | \"blob\" => url_to_filename(&url)?,\n  other => {\n    return Err(std::io::Error::new(\n      std::io::ErrorKind::InvalidInput,\n      format!(\"unsupported cache scheme: {other}\"),\n    ))\n  }\n};","handlingStrategy":"validation","validationCode":"fn is_cacheable_url(url: &url::Url) -> bool {\n  matches!(url.scheme(), \"http\" | \"https\" | \"data\" | \"blob\")\n}\n\n// before caching:\nif !is_cacheable_url(&url) {\n  return Err(std::io::Error::new(\n    std::io::ErrorKind::InvalidInput,\n    format!(\"cannot cache non-remote url: {url}\"),\n  ));\n}\nlet path = url_to_filename(&url)?;","typeGuard":null,"tryCatchPattern":"match url_to_filename(&url) {\n  Ok(path) => { /* use path */ }\n  Err(err) if err.kind() == std::io::ErrorKind::InvalidInput => {\n    // unsupported scheme (not http/https/data/blob) — handle locally or skip caching\n  }\n  Err(err) => return Err(err),\n}","preventionTips":["Normalize specifiers at your system's boundary: resolve file:/bare/custom specifiers to concrete paths before anything reaches the remote cache.","Keep a whitelist of schemes your loader supports and validate URLs against it before calling cache APIs.","Log the scheme (not just the URL) when caching fails so scheme regressions are obvious in CI."],"tags":["url","cache","scheme","invalid-input","deno"],"backgroundTag":"unsupported-url-scheme","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}