tonhowtf/omniget · error
vimeo:is_a_collection
vimeo:is_a_collection
Error message
vimeo:is_a_collection
What it means
vimeo:is_a_collection is raised by `private` when the URL parses successfully but points to a collection (showcase, album, channel, or user profile) rather than a single video. The private-video path downloads exactly one video, so collection targets are rejected with this dedicated code.
Solutions
- Route the request to `list` (enumerate) or `backup` (batch download) instead of `private`.
- Ensure the URL is a single video: https://vimeo.com/<numeric-id> or /<id>/<hash>.
- In the caller, use the parsed target kind (video vs showcase/album/channel/user) to pick the correct API before invoking.
- Fix UI validation so collection URLs cannot be submitted in the private-video form.
Example fix
// before
await vimeoPrivate({ url: "https://vimeo.com/showcase/9911" });
// after
if (/vimeo\.com\/(showcase|album|channels)\//.test(url) || !/\d+/.test(url.split("/").pop() ?? "")) {
await vimeoList({ url });
} else {
await vimeoPrivate({ url });
} Defensive patterns
Strategy: validation
Validate before calling
const COLLECTION_RE = /vimeo\.com\/(showcase|album|channels)\//;
function isProfileUrl(u) {
const s = (u ?? "").trim();
return /^https:\/\/vimeo\.com\/[a-zA-Z][\w-]*\/?$/.test(s);
}
if (COLLECTION_RE.test(opts.url) || isProfileUrl(opts.url)) {
return vimeoList({ url: opts.url }); // route to collection flow instead
} Type guard
function isSingleVideoTarget(u) {
return /^(https:\/\/vimeo\.com\/\d+|\d+)(\/[a-z0-9]+)?$/.test((u ?? "").trim());
} Try / catch
try {
await vimeoPrivate({ url });
} catch (e) {
if (String(e).includes("vimeo:is_a_collection")) {
showError("That URL is a collection — use batch download instead");
} else throw e;
} Prevention
- Classify the URL (video vs collection) once, centrally, and pick the API from the kind
- Disable the private-video form for collection URLs in the UI
- Numeric-id URLs are videos; username-shaped URLs are profiles — encode that rule in routing
When it happens
Trigger: Calling `private(opts)` with opts.url such as https://vimeo.com/showcase/123456, /album/<id>, /channels/<name>, or /<username> — anything where `target.is_collection()` is true.
Common situations: User pastes their portfolio/profile URL into the single-video field; mixing up the 'download collection' and 'download private video' features in the UI; automated routing not distinguishing video ids from usernames.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- vimeo:not_a_collection
- vimeo:bad_url
- o yt-dlp devolveu um JSON que não deu para ler
- o yt-dlp não está disponível
- não foi possível iniciar o yt-dlp
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/1b3b23bac063d2a3.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/tools/vimeo.rs:1095
kind: target.kind().to_string(),
title,
dest: dest.to_string_lossy().to_string(),
total,
ok,
skipped,
failed,
items,
used_session,
command: last_command,
})
}
/// Um vídeo privado ou unlisted. O hash já vai na URL; a senha, quando existe,
/// vai em `--video-password` e nunca sai daqui.
pub async fn private(opts: &PrivateOptions, progress: &ProgressFn) -> Result<PrivateResult> {
let target = parse_target(&opts.url).ok_or_else(|| anyhow!("vimeo:bad_url"))?;
if target.is_collection() {
return Err(anyhow!("vimeo:is_a_collection"));
}
let (id, unlisted_hash) = match &target {
Target::Video { id, hash } => (id.clone(), hash.is_some()),
_ => (String::new(), false),
};
let url = target.canonical_url();
let dest = PathBuf::from(&opts.dest);
std::fs::create_dir_all(&dest)?;
let bin = ytdlp_bin().await?;
let ffmpeg = crate::core::dependencies::find_tool("ffmpeg").await;
let cookies = cookie_file(opts.session_netscape.as_deref());
let used_session = cookies.is_some();
let secrets = secret_refs(opts.video_password.as_ref(), None);
let used_password = opts
.video_password
.as_deref()
.map(|p| !p.is_empty())
.unwrap_or(false);View on GitHub (pinned to 8600b91f42)