HTTP Video Streaming Header Requirements
SkillWeb & browsingFix "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.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the HTTP Video Streaming Header Requirements skill
What this skill tells your AI
The instructions your AI receives, as published by divinevideo/divine-mobile in .agents/skills/http-video-streaming-headers/SKILL.md and read by ahel’s review.
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
onerrorevent 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
-
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
-
Content-Type: video/mp4(or appropriate MIME type)- Must match actual video format
- Browser uses this to select decoder
-
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
-
For Range Requests (206 Partial Content):
Content-Range: bytes START-END/TOTAL- Status code MUST be 206, not 200
Server Implementation
// 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
# 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: bytesin 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
Signals
- GitHub stars
- 265
- Forks
- 55
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
http-video-streaming-headers- Source
- github.com/divinevideo/divine-mobile