tonhowtf/omniget · error

esse clipe não tem VOD de origem, então não há chat

Error message

esse clipe não tem VOD de origem, então não há chat

What it means

clip_video() throws this when the clip exists but its video.id pointer is absent, i.e. the clip has no source VOD. Chat replay is stored on the VOD, so without a source video there is no chat to download for a clip. The library refuses rather than returning a video-less result.

Solutions

  1. Accept that clip chat is unavailable and download the chat of an available VOD instead
  2. Locate another clip of the same stream whose source VOD still exists
  3. If the channel reuploaded/saved the stream, resolve the VOD id and use video()/fetch_all directly
  4. Handle this error distinctly from 'clip not found' in caller UX

Example fix

// before
let target = resolve_chat_target(&arg).await?; // may be a sourceless clip
// after
let target = match resolve_chat_target(&arg).await {
    Ok(t) => t,
    Err(e) if e.to_string().contains("não tem VOD de origem") => {
        eprintln!("clip has no source VOD; no chat replay exists");
        return Err(e);
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Not checkable pre-call via this API; the clip's source-VOD link is only in the response.

Try / catch

match gql.clip_video(slug).await {
    Err(e) if e.to_string().contains("não tem VOD de origem") => {
        eprintln!("Clip exists but its source stream has no saved VOD — no chat replay");
        Ok(())
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling gql.clip_video(slug) (or resolve_chat_target with a clip) for a clip whose source broadcast was deleted or expired after the clip was created, or clips made in contexts without an attached VOD.

Common situations: Old clips whose source stream was never saved or later deleted/expired; clips on channels that never keep VODs; asking for chat download on such a clip instead of the original stream's VOD.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/4f13772fb33c42b5. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/tools/twitch/gql.rs:255

            created_at: str_at(v, "createdAt"),
            clip_offset: None,
            clip_duration: None,
        })
    }

    /// Clipe → VOD de origem, com a janela do clipe dentro dele.
    pub async fn clip_video(&self, slug: &str) -> anyhow::Result<VideoInfo> {
        let q = format!(
            r#"{{ clip(slug: "{}") {{ durationSeconds videoOffsetSeconds video {{ id }} }} }}"#,
            escape(slug)
        );
        let data = self.query(&q).await?;
        let c = data.get("clip").filter(|v| !v.is_null());
        let c = c.ok_or_else(|| anyhow!("clipe não encontrado: {}", slug))?;
        let vid = c
            .pointer("/video/id")
            .and_then(|x| x.as_str())
            .ok_or_else(|| anyhow!("esse clipe não tem VOD de origem, então não há chat"))?;
        let mut info = self.video(vid).await?;
        info.clip_offset = c.get("videoOffsetSeconds").and_then(num);
        info.clip_duration = c.get("durationSeconds").and_then(num);
        Ok(info)
    }

    /// Resolve o que o usuário colou até chegar num VOD.
    pub async fn resolve_chat_target(&self, input: &str) -> anyhow::Result<VideoInfo> {
        let target = parse_video(input)
            .ok_or_else(|| anyhow!("cole o link de um VOD ou de um clipe da Twitch: {}", input))?;
        match target {
            ChatTarget::Video(id) => self.video(&id).await,
            ChatTarget::Clip(slug) => self.clip_video(&slug).await,
        }
    }
}

fn num(v: &Value) -> Option<f64> {

View on GitHub (pinned to 8600b91f42)