calesthio/OpenMontage · warning · RuntimeError

Dareful download failed for {detail_url}: {e}

Error message

Dareful download failed for {detail_url}: {e}

What it means

RuntimeError raised by the Dareful adapter's outer except block, wrapping any exception raised during download — including the 'Could not find download URL' ValueError (356), HTTP failures inside _stream_download (raise_for_status on 403/404/5xx), timeouts, or parsing errors. The original exception is chained via 'from e', so the '{e}' suffix preserves the root cause.

Source

Thrown at tools/video/stock_sources/dareful.py:173

            # Check video elements
            if not download_url:
                for source in soup.select("video source[src], video[src]"):
                    src = source.get("src", "")
                    if src:
                        download_url = src
                        break

            if not download_url:
                raise ValueError(f"Could not find download URL on Dareful page: {detail_url}")

            if not download_url.startswith("http"):
                download_url = f"{_BASE_URL}{download_url}"

            return self._stream_download(download_url, out_path)

        except Exception as e:
            raise RuntimeError(f"Dareful download failed for {detail_url}: {e}") from e

    def _stream_download(self, url: str, out_path: Path) -> Path:
        import requests

        with requests.get(
            url, stream=True, timeout=180,
            headers={"User-Agent": "OpenMontage/1.0"},
        ) as r:
            r.raise_for_status()
            with open(out_path, "wb") as f:
                for chunk in r.iter_content(chunk_size=1 << 16):
                    if chunk:
                        f.write(chunk)
        return out_path

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Inspect the chained cause (raise's __cause__) to identify whether it was scraping, HTTP, or timeout.
  2. Treat Dareful failures as per-clip, not fatal: catch, log, continue the batch, and backfill from another source.
  3. For repeated 403s, fetch the file URL with a real browser session and download directly.
  4. For timeouts on large clips, retry once — transient origin slowness is common.

Example fix

# before
paths = [dareful.download(c, out) for c in candidates]

# after
paths = []
for c in candidates:
    try:
        paths.append(dareful.download(c, out))
    except RuntimeError as e:
        logger.warning("dareful clip %s failed: %s", c.clip_id, e.__cause__ or e)
Defensive patterns

Strategy: fallback

Try / catch

for c in candidates:
    try:
        paths.append(dareful.download(c, out))
    except RuntimeError as e:
        logger.warning("dareful %s failed (%s), continuing", c.clip_id, e.__cause__ or e)
        continue

Prevention

When it happens

Trigger: Any of: selector miss on the detail page, expired/signed download URL returning 403, bot-detection 403 on the media host, requests.Timeout after 180s, or BeautifulSoup parse exceptions — all re-thrown under this unified message.

Common situations: Bulk corpus builds where a fraction of Dareful links have expired; UA-based blocking (mitigated by the adapter's OpenMontage/1.0 User-Agent, but aggressive edges still block); slow origin timing out mid-stream.

Related errors


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/ffc88096e0b62678. Report an issue: GitHub.