Skip to content
cccskills
FreePublished on GitHub

http-video-streaming-headers

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.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md3.9 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

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

// 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: 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

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Fix ArgoCD ExternalSecret deployment failing with "namespace X is not permitted in project Y". Use when: (1) ExternalSecret shows OutOfSync in ArgoCD but won't sync, (2) ArgoCD application status shows "namespace X is not permitted in project 'infrastructure'", (3) ExternalSecret targets a namespace managed by a different ArgoCD project, (4) Using apps-of-apps pattern with separate infrastructure and application projects.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Art direction for any content — reads text, PDF, Word, HTML, PPT, then proposes 2-3 creative directions with photography style, mood, and visual language. After selection, generates AI image prompts and visual briefs section-by-section. Use when the user shares content and needs visual direction, image sourcing, or creative direction for any material.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Fix "Null check operator used on a null value" errors when an object is set to null during an async await. Use when: (1) Object reference is nullified while awaiting, (2) Code accesses object with ! after await returns, (3) Cancel/dispose operations run concurrently with async operations on same object. Solution: capture local reference before await.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Add custom metadata headers (x-amz-meta-*) to AWS v4 signed requests for GCS S3-compatible API. Use when: (1) Adding custom metadata to GCS uploads via S3 API, (2) Getting signature mismatch errors after adding new headers, (3) x-amz-meta-* headers being ignored or causing 403 errors. Custom headers MUST be included in canonical headers and signed headers list.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Fix password/secret authentication failures caused by trailing newlines when creating Google Cloud secrets (or similar) with bash here-strings. Use when: (1) Password authentication fails with correct password, (2) Secret created with `<<< "value"` syntax, (3) Error like "password authentication failed" or "invalid token" despite correct value. Bash here-strings (`<<<`) add a trailing newline that corrupts secrets.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

Fix silent video/media processing failures caused by URL extraction code that filters on file extensions (.mp4, .webm, .webp). Use when: (1) Media moderation, transcoding, or analysis silently skips files from Blossom or content-addressed storage servers, (2) URL extraction from Nostr event tags (imeta, r tags) drops URLs without recognized extensions, (3) CDN fallback URLs append .mp4 but the actual server uses extensionless content-addressed paths like /{sha256}. Common in Nostr video events (kind 34236) where different clients use different URL formats.

The English summary is being prepared. Showing the original description.

divinevideo/divine-mobile266Updated Oct 19, 2026

See all skills by divinevideo

Report a problem with this skill