tonhowtf/omniget · error · anyhow::Error

Failed to detect URL kind

Error message

Failed to detect URL kind: {}

What it means

`api_engine_download` resolves b23.tv short links, then calls `url_kind::detect(&effective_url)` to classify the URL (video, audio, article, etc.). If detection fails, the error's i18n key is wrapped with `anyhow!("Failed to detect URL kind: {}")`. Without a kind, the engine cannot choose a parser.

Solutions

  1. Verify the URL is a supported Bilibili content URL (video BV/AV, etc.) before calling download.
  2. Ensure b23.tv short links can be resolved (network access); paste the expanded URL if resolution fails.
  3. Update the app — new Bilibili URL formats require updated detection rules.
  4. Map the error's i18n key to a user-facing message and prompt for a corrected link.

Example fix

// before
let url = "https://example.com/not-bilibili";
download(info_from(url), opts, progress).await?; // Failed to detect URL kind
// after
if !url.contains("bilibili.com") && !url.contains("b23.tv") {
    return Err(anyhow!("not a Bilibili URL"));
}
download(info_from(url), opts, progress).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn looks_like_bilibili(url: &str) -> bool {
    url.contains("bilibili.com") || url.contains("b23.tv")
}
if !looks_like_bilibili(&effective_url) { return Err(anyhow!("unsupported URL")); }

Try / catch

match download(info, opts, progress).await {
    Err(e) if e.to_string().contains("Failed to detect URL kind") => ask_user_for_valid_link(),
    Err(e) => return Err(e),
    Ok(_) => {},
}

Prevention

When it happens

Trigger: Calling `download` with a URL that `url_kind::detect` cannot classify — not a valid Bilibili URL at all, a b23.tv link that failed to resolve and remains a short URL, malformed video ID/BV numbers, or unsupported URL shapes (live rooms, space pages) the detector doesn't handle.

Common situations: Users pasting arbitrary web pages or non-Bilibili links; b23.tv short-link resolution failing due to network/redirect changes; new Bilibili URL formats not yet supported by the detector; typos in BV/AV ids.

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 tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/968a00486e128873. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/platforms/bilibili/mod.rs:122

        .first()
        .map(|q| q.url.as_str())
        .unwrap_or("");
    if url.is_empty() {
        return Err(anyhow!("No URL available"));
    }

    let slug = active_account_slug();
    let client = build_api_client(slug.as_deref(), opts.user_agent.as_deref())?;

    let mut effective_url = url.to_string();
    if url_kind::is_b23_short(&effective_url) {
        if let Ok(resolved) = url_kind::resolve_b23(&client, &effective_url).await {
            effective_url = resolved;
        }
    }

    let kind = url_kind::detect(&effective_url)
        .map_err(|e| anyhow!("Failed to detect URL kind: {}", e.i18n_key()))?;
    let parsed = parser::parse(&client, &kind)
        .await
        .map_err(|e| anyhow!("Failed to parse content: {}", e.i18n_key()))?;

    let settings = crate::storage::config::load_settings_standalone();
    let container = mux::container_from_setting(&settings.download.bilibili_container);
    let danmaku_format = danmaku_format_from_setting(&settings.download.bilibili_danmaku_format);
    let cover_format = cover::CoverFormat::from_str(&settings.download.bilibili_cover_format);
    let template_set = naming::TemplateSet {
        video: settings.download.bilibili_naming_video.clone(),
        multi_part: settings.download.bilibili_naming_multi_part.clone(),
        bangumi: settings.download.bilibili_naming_bangumi.clone(),
        cheese: settings.download.bilibili_naming_cheese.clone(),
        collection: settings.download.bilibili_naming_collection.clone(),
    };
    let first_item_owned = parsed.items.first().cloned().unwrap_or_default();
    let naming_kind = naming::classify(&kind, &first_item_owned);
    let naming_inputs = naming::NamingInputs {

View on GitHub (pinned to 8600b91f42)