Hmbown/CodeWhale · error
invalid bundle URL
Error message
invalid bundle URL
What it means
`fetch_bundle` first parses the given bundle URL with `reqwest::Url::parse`; any parse failure is mapped to this error. It is thrown before any network activity, so it always means the URL string itself is not a valid absolute URL.
Solutions
- Pass a full absolute URL including the scheme: `https://host/path` (plain `http://` is only accepted for loopback hosts).
- Trim whitespace and shell-quoting artifacts from the URL.
- For local bundles, use the file/import-from-path flow rather than a URL.
Example fix
// before codewhale config-bundles import example.com/bundle.zip // after codewhale config-bundles import https://example.com/bundle.zip
Defensive patterns
Strategy: validation
Validate before calling
fn is_fetchable_bundle_url(s: &str) -> bool {
match reqwest::Url::parse(s) {
Ok(u) => matches!(u.scheme(), "https") || (u.scheme() == "http" && u.host_str().map_or(false, |h| h == "localhost" || h == "127.0.0.1")),
Err(_) => false,
}
} Type guard
fn is_absolute_https(s: &str) -> bool {
reqwest::Url::parse(s).map(|u| u.scheme() == "https").unwrap_or(false)
} Prevention
- Always include the scheme in bundle URLs.
- Trim and shell-quote URLs passed on the command line.
- Use file paths, not URLs, for local bundles.
When it happens
Trigger: `fetch_bundle` / `codewhale` bundle import invoked with a URL string that fails RFC 3986 parsing — missing scheme (`example.com/bundle.zip`), invalid characters, empty string, or a relative path.
Common situations: Forgetting the `https://` scheme; copying a URL with surrounding whitespace or shell-mangled characters; passing a local file path instead of a URL.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- --base-url must use http or https
- Codewhale account API base URL must be an origin without a…
- Codewhale account API base URL must not contain a query or…
- invalid --base-url
- A positive pull request number is required
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/adf2c66ee19027f3.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/config_bundles.rs:754
"could not resolve bundle path component {}",
deepest_existing.display()
)
})?;
if !resolved.starts_with(&canonical_base) {
bail!("bundle path {candidate:?} escapes the config directory via a symlink; refused");
}
Ok(joined)
}
// ---------------------------------------------------------------------------
// Remote fetch
// ---------------------------------------------------------------------------
/// Fetch a bundle over HTTPS (or plain http on loopback only) with a hard
/// size cap, a timeout, and bounded redirects. Mirrors the skill installer's
/// fetch bounds.
pub fn fetch_bundle(url: &str) -> Result<Vec<u8>> {
let mut current_url = reqwest::Url::parse(url).map_err(|_| anyhow!("invalid bundle URL"))?;
validate_bundle_url(¤t_url)?;
let initial_scheme = current_url.scheme().to_string();
let client = codewhale_release::platform_blocking_http_client_builder()
.timeout(std::time::Duration::from_secs(FETCH_TIMEOUT_SECS))
// Redirect targets must pass the same scheme/host policy as the
// initial request, so redirects are followed explicitly below.
.redirect(reqwest::redirect::Policy::none())
.build()
.map_err(|_| anyhow!("building bundle fetch client failed"))?;
let mut redirects = 0usize;
let response = loop {
let response = client
.get(current_url.clone())
.send()
// reqwest errors can include the full URL (including its query or
// userinfo), so keep transport failures deliberately URL-free.
.map_err(|_| anyhow!("bundle fetch request failed"))?;View on GitHub (pinned to 73e0f67d83)