# How to Troubleshoot Download Errors in ReClip: A Complete Diagnostic Guide

> Troubleshoot ReClip download errors efficiently. Inspect job status details and yt-dlp diagnostics to resolve specific failures with this comprehensive guide.

- Repository: [Avery Gan/reclip](https://github.com/averygan/reclip)
- Tags: how-to-guide
- Published: 2026-09-05

---

**ReClip delegates video downloads to yt-dlp through a Flask backend with a 5-minute timeout, storing granular error details in the job status endpoint that you can inspect to diagnose specific failures.**

The open-source ReClip repository (`averygan/reclip`) provides a web interface for downloading videos and audio using yt-dlp. Understanding how to troubleshoot download errors requires familiarity with its three-stage architecture: request handling in `/api/download`, background execution via `run_download` in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py), and status polling through `/api/status/<job_id>`. When failures occur, ReClip captures stderr output, timeout conditions, and file system states to help you pinpoint whether the issue stems from yt-dlp configuration, network constraints, or environment permissions.

## Understanding the Download Architecture

ReClip processes downloads through a job queue system implemented in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py). When you submit a URL to `/api/download`, the backend spawns a daemon thread that executes `run_download` with your specified format parameters.

The `run_download` function (lines 36-89 in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py)) constructs the yt-dlp command based on your selection between audio extraction (`-x --audio-format mp3`) or video download with specific format IDs. It executes this command via `subprocess.run` with a hardcoded **300-second timeout** (5 minutes) and captures both stdout and stderr. Upon completion, it either locates the generated file in the `downloads/` directory and sets `job["status"] = "done"`, or captures the error output and sets `job["status"] = "error"` along with the specific failure message.

## Common Download Error Patterns and Code Paths

### yt-dlp Command Execution Failures

When yt-dlp returns a non-zero exit code, `run_download` captures the final line of stderr and stores it in `job["error"]` (lines 49-52 in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py)). This typically indicates unsupported URLs, geo-blocking, or missing cookies for authenticated content.

**Diagnostic signature:** Check the job status endpoint and look for error messages containing yt-dlp-specific output like "ERROR:" or "Unsupported URL".

### Timeout Expiration (5-Minute Limit)

Large files or slow network connections trigger `subprocess.TimeoutExpired`, which `run_download` catches at lines 84-86 in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py). The system sets `job["error"]` to "Download timed out (5 min limit)" and terminates the subprocess.

**Verification:** Inspect your job status JSON for the exact timeout message. If the target video exceeds 1GB or your bandwidth is constrained, this is the likely culprit.

### Missing Output Files After Success

Even when yt-dlp exits successfully, `run_download` uses `glob.glob` (lines 54-58 in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py)) to locate files matching `downloads/{job_id}.*`. If this returns an empty list—often due to permission issues or incorrect output templates—the job status indicates completion but `/api/file/<job_id>` returns no content.

**Check:** Verify the `downloads/` directory exists, is writable by the Flask process, and that yt-dlp actually wrote files with the expected `{job_id}` prefix.

### Binary Permission and Path Issues

If `yt-dlp` or `ffmpeg` are absent from the system `$PATH`, the subprocess fails immediately before network operations begin. Unlike yt-dlp content errors, these manifest as file-not-found or permission-denied errors in the job error field.

**Fix:** Confirm binary availability by running `yt-dlp --version` and `ffmpeg -version` in the same environment (Docker container or host) where [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) executes.

## Step-by-Step Troubleshooting Workflow

Follow this diagnostic sequence to resolve download failures systematically:

1. **Inspect the job error payload**
   Query the status endpoint to retrieve the exact error message stored during execution:
   ```bash
   curl -s http://localhost:8899/api/status/<job_id> | jq .
   ```

   Examine the `"error"` key for the specific yt-dlp output or timeout notification.

2. **Reproduce the yt-dlp command locally**
   ReClip builds commands dynamically in `run_download` (lines 36-44 in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py)). Reconstruct and run this command manually to isolate environment issues:
   ```bash
   yt-dlp --no-playlist -x --audio-format mp3 \
     -o "downloads/<job_id>.%(ext)s" "<YOUR_URL>"
   ```

3. **Verify the download directory**
   Ensure the `downloads/` folder exists and permits write access:
   ```bash
   ls -l downloads/
   touch downloads/test_write && rm downloads/test_write
   ```

4. **Adjust the subprocess timeout**
   For large files, modify the timeout parameter in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) at line 48:
   ```python
   result = subprocess.run(
       cmd,
       capture_output=True,
       text=True,
       timeout=1800  # 30 minutes instead of 300

   )
   ```

5. **Validate Docker volume mounts**
   If running containerized, confirm the `downloads/` directory is mounted as a persistent volume in your `docker run` command or [`docker-compose.yml`](https://github.com/averygan/reclip/blob/main/docker-compose.yml), preventing data loss when containers restart.

## Practical Debugging Examples

### Polling Job Status with Error Handling

Use this JavaScript pattern to gracefully handle download failures in the frontend:

```javascript
async function pollStatus(jobId) {
  const resp = await fetch(`/api/status/${jobId}`);
  const data = await resp.json();

  if (data.status === 'error') {
    console.error(`Download failed: ${data.error}`);
    alert(`Download error: ${data.error}`);
  } else if (data.status === 'done') {
    window.location.href = `/api/file/${jobId}`;
  } else {
    setTimeout(() => pollStatus(jobId), 2000);
  }
}

```

### Manual yt-dlp Testing for Format Selection

When specific format IDs fail, test them directly outside ReClip:

```bash
JOB_ID="debug_$(date +%s)"
URL="https://www.youtube.com/watch?v=example"

# Test audio extraction

yt-dlp --no-playlist -x --audio-format mp3 \
  -o "downloads/${JOB_ID}.%(ext)s" "$URL"

# Or test specific video format

yt-dlp --no-playlist -f "137+140" \
  -o "downloads/${JOB_ID}.%(ext)s" "$URL"

```

### Extending Timeout in the Flask Backend

For deployments handling 4K or long-form content, edit [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) to increase the timeout threshold:

```python

# In app.py, run_download function

try:
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        timeout=1800  # 30 minutes for large files

    )
except subprocess.TimeoutExpired:
    job["status"] = "error"
    job["error"] = "Download timed out (30 min limit)"
    return

```

## Summary

- **ReClip uses yt-dlp** executed through Python's `subprocess` module in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py), with a default 300-second timeout that commonly triggers on large files or slow connections.
- **Error messages are granular**—check `/api/status/<job_id>` to see whether the failure stems from yt-dlp stderr, timeout expiration, or missing output files in the `downloads/` directory.
- **Local reproduction is key**—reconstruct the exact command from `run_download` (lines 36-44) and execute it manually to bypass Flask-specific issues.
- **Binary dependencies matter**—ensure both `yt-dlp` and `ffmpeg` are installed and accessible in the `$PATH` of the execution environment, whether native or Dockerized.

## Frequently Asked Questions

### Why does my download fail immediately with a yt-dlp error?

Immediate failures typically indicate that yt-dlp cannot process the URL. According to the error handling in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) (lines 49-52), ReClip stores the final line of yt-dlp's stderr in the job error field. Common causes include unsupported platforms, geo-restricted content, or missing authentication cookies. Run the same URL with yt-dlp locally to see the full error output.

### How do I fix "Download timed out" errors in ReClip?

ReClip enforces a 5-minute (300-second) timeout on the subprocess call in `run_download` ([`app.py`](https://github.com/averygan/reclip/blob/main/app.py) lines 48-50). For large videos or slow connections, increase this value by modifying the `timeout` parameter to 1800 (30 minutes) or higher. Alternatively, use yt-dlp's `-f` flag to select lower-resolution formats that download faster.

### Why is the downloaded file missing even though the status shows "done"?

This occurs when `glob.glob` in [`app.py`](https://github.com/averygan/reclip/blob/main/app.py) (lines 54-58) cannot locate files matching `downloads/{job_id}.*` after yt-dlp exits successfully. Verify that the Flask process has write permissions to the `downloads/` directory and that the directory exists before starting the server. In Docker deployments, ensure the volume mount persists between the download completion and file retrieval request.

### Can I run ReClip without Docker to debug yt-dlp issues?

Yes, running the Flask backend directly simplifies debugging. Install dependencies from [`requirements.txt`](https://github.com/averygan/reclip/blob/main/requirements.txt), ensure `yt-dlp` and `ffmpeg` are in your system PATH, then execute `python app.py`. This allows you to add `print(cmd)` statements in `run_download` to see the exact command being executed and observe real-time yt-dlp output without container abstraction layers.