Fix "Failed to load video" errors when network requests succeed (200/206 status). Use when: (1) Video element shows error but DevTools shows successful requests, (2) Videos download correctly via curl but fail in browser, (3) Range requests work but video won't play, (4) Building CDN/media server for video streaming. The root cause is often missing Accept-Ranges header which browsers need for video seeking and streaming.
Scanned 9/3/2026
Install to Claude Code
npx -y skills add divinevideo/divine-mobile --skill http-video-streaming-headers --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Http Video Streaming Headers?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/divinevideo-http-video-streaming-headers-divine-mobile)More formats (shields.io, HTML) on the badges page.
---
name: http-video-streaming-headers
description: |
Fix "Failed to load video" errors when network requests succeed (200/206 status).
Use when: (1) Video element shows error but DevTools shows successful requests,
(2) Videos download correctly via curl but fail in browser, (3) Range requests
work but video won't play, (4) Building CDN/media server for video streaming.
The root cause is often missing Accept-Ranges header which browsers need for
video seeking and streaming.
author: Claude Code
version: 1.0.0
date: 2026-01-29
---
# HTTP Video Streaming Header Requirements
## Problem
HTML5 video elements fail to play with "Failed to load video" error even though
network requests show successful 200/206 responses. The video file downloads
correctly when tested with curl, but browsers refuse to play it.
## Context / Trigger Conditions
- Video element fires `onerror` event despite network success
- DevTools Network tab shows 200 or 206 status for video requests
- `curl -O <video-url>` downloads a valid MP4 file
- Video plays locally when downloaded
- Error message is generic: "Failed to load video" or media error code 4
## Solution
### Required Headers for Video Streaming
1. **`Accept-Ranges: bytes`** (CRITICAL)
- Tells browser that range requests are supported
- Without this, browsers may not attempt range requests for seeking
- Add to ALL video responses, even full (200) responses
2. **`Content-Type: video/mp4`** (or appropriate MIME type)
- Must match actual video format
- Browser uses this to select decoder
3. **`Content-Length`** (for full responses)
- Required for browser to know file size
- Enables progress indicators and seeking calculations
- Note: For 206 responses, this should be partial content size
4. **For Range Requests (206 Partial Content)**:
- `Content-Range: bytes START-END/TOTAL`
- Status code MUST be 206, not 200
### Server Implementation
```rust
// Fastly Compute@Edge example
resp.set_header("Accept-Ranges", "bytes");
resp.set_header("Content-Type", "video/mp4");
// For full responses only (not 206):
if resp.get_status() != StatusCode::PARTIAL_CONTENT {
resp.set_header("Content-Length", file_size.to_string());
}
```
### CDN Considerations
- Edge caches may strip or modify headers
- Verify headers reach the client, not just origin
- Fastly/CloudFront can serve range requests from cached full content
- Test with `curl -I -H "Range: bytes=0-1023"` to verify 206 response
## Verification
```bash
# Check Accept-Ranges header
curl -I https://cdn.example.com/video.mp4 | grep -i accept-ranges
# Expected: accept-ranges: bytes
# Test range request support
curl -I -H "Range: bytes=0-1023" https://cdn.example.com/video.mp4
# Expected: HTTP/2 206 with Content-Range header
# Verify partial download works
curl -H "Range: bytes=0-100" https://cdn.example.com/video.mp4 | wc -c
# Expected: 101 (bytes 0-100 inclusive)
```
## Example
**Before (broken)**:
```
HTTP/2 200
content-type: video/mp4
x-custom-header: value
```
Video fails to load in browser.
**After (working)**:
```
HTTP/2 200
content-type: video/mp4
content-length: 1443199
accept-ranges: bytes
```
Video plays correctly with seeking support.
## Notes
- Even if your CDN handles range requests automatically, you should still
include `Accept-Ranges: bytes` in the response headers
- Some browsers are more forgiving than others; Safari often requires
proper range support while Chrome may work without
- HTTP/2 responses may have headers lowercased (this is normal)
- For HLS/DASH streaming, the manifest and segments all need proper headers
- Mobile browsers are particularly strict about video headers
## References
- [MDN: Range Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests)
- [MDN: Accept-Ranges](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Ranges)
- [HTTP 206 Partial Content](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!