tonhowtf/omniget · error · anyhow::Error
Failed to parse content
Error message
Failed to parse content: {} What it means
After URL detection succeeds, `api_engine_download` calls `parser::parse(&client, &kind)` to fetch and interpret content metadata via the Bilibili API; any parser error's i18n key is wrapped in `anyhow!("Failed to parse content: {}")`. This is the top-level wrapper for all upstream API/parse failures.
Solutions
- Read the wrapped i18n key to identify the underlying cause (auth, not-found, rate-limit) and address it specifically.
- Refresh login credentials/cookies for the active account.
- Retry after a delay if rate-limited; use a realistic User-Agent via `opts.user_agent`.
- Update the app/parsers if Bilibili's API format changed.
- Confirm the content still exists and is publicly playable in a browser.
Example fix
// before
let parsed = parser::parse(&client, &kind).await.map_err(|e| anyhow!("Failed to parse content: {}", e.i18n_key()))?;
// after
let parsed = match parser::parse(&client, &kind).await {
Ok(p) => p,
Err(e) if is_auth_error(&e) => { refresh_cookies(&client).await?; parser::parse(&client, &kind).await? }
Err(e) => return Err(anyhow!("Failed to parse content: {}", e.i18n_key())),
}; Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight: ensure account/cookies are configured before parsing
if active_account_slug().is_none() && content_requires_login(&kind) {
return Err(anyhow!("login required"));
} Try / catch
match download(info, opts, progress).await {
Err(e) if e.to_string().contains("Failed to parse content") => {
log_parse_error(&e); // inspect i18n key: auth vs not-found vs rate-limit
maybe_refresh_credentials_and_retry().await?;
}
Err(e) => return Err(e),
Ok(_) => {},
} Prevention
- Keep Bilibili cookies/credentials fresh for the active account.
- Back off and retry on rate-limit/anti-bot responses; set a realistic User-Agent.
- Update the app when Bilibili API formats change.
- Inspect the i18n key inside the error to route auth, not-found, and network failures to different handlers.
When it happens
Trigger: Calling `download` where the Bilibili API request inside `parser::parse` fails — HTTP errors, rate limiting, login-required/charge-only content, deleted or private videos, API response shape changes breaking the parser, or invalid account credentials/cookies.
Common situations: Expired Bilibili cookies causing auth-required responses; region-restricted content returning unavailable; Bilibili changing its API JSON structure after an app update gap; network failures or 412/429 anti-bot responses from Bilibili.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse content
- YouTube não retornou URL
- HTTP
- Twitch recusou o replay de chat
- Twitch GQL respondeu HTTP
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/98dce1cc8edf11bd.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/platforms/bilibili/mod.rs:125
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 {
item: &first_item_owned,
metadata: &parsed.metadata,
parsed_title: &parsed.title,View on GitHub (pinned to 8600b91f42)