Why a supported video format still fails to play

Separate container support, codec profiles, decoding performance and network delivery when diagnosing media playback.

A browser saying probably to a media type is not the same as a video playing successfully. The file can contain a different codec profile, the server can return the wrong bytes, the decoder can struggle with the resolution, or playback can be blocked until the user interacts with the page.

Work through the failure in layers: identify the media, check the browser's support hint, inspect delivery, attempt playback and measure performance. This sequence keeps a network error from being misdiagnosed as a codec problem and a playback-policy rejection from being mistaken for a broken file.

Separate the container from the codec

A container packages streams and metadata. A codec defines how a stream is encoded and decoded. MP4 and WebM are container families; H.264, AV1, VP9 and Opus describe codecs. A filename ending in .mp4 does not fully describe the video and audio streams inside it.

The media support checker asks the browser about a fixed set of MIME types and codec strings. It reports those answers without downloading or playing your media file. Its result is therefore a preliminary compatibility hint for the listed combinations.

When a real asset fails, obtain its actual stream metadata from your encoding pipeline or a media inspection utility. Record codec, profile, level, dimensions, frame rate and audio configuration. A browser's answer for a baseline H.264 example cannot establish support for every possible H.264 stream.

Interpret canPlayType carefully

HTMLMediaElement.canPlayType returns an empty string, maybe or probably. An empty string indicates that the browser does not claim support for the supplied type. Maybe and probably are degrees of support confidence, not successful decoding results.

Supply a meaningful MIME type and codec parameter when you know them. A broad container-only query gives the browser less information. Keep the exact query in the report; otherwise two developers can compare different hints while believing they tested the same format.

A support hint also does not promise smooth decoding or low power use. A device may decode a stream in software, struggle at high resolution or use more energy than expected. Those questions require more detailed capability information and a representative playback test.

Locate the layer that failed
SymptomEvidence to inspectLikely investigation
Unsupported type hintExact MIME and codec stringContainer and codec compatibility
Request returns an HTML pageStatus, content type and response bodyRouting, authentication or CDN configuration
play promise rejectsError name and user interactionPlayback policy or unsupported media
Video plays with dropped framesResolution, frame rate and decode metricsPerformance and delivery
Seeking failsRange requests and file structureServer support and media packaging

Inspect the actual response before re-encoding

Open the network panel and select the media request. Confirm that the URL returns media bytes rather than a login page, an error document or a redirect loop. A status of 200 is not enough if the body is an HTML fallback generated by the application router.

Review content type, content length where available and byte-range behaviour. Media seeking and progressive loading can involve range requests. The server and CDN must handle them consistently with the asset. A partial response containing the wrong byte range can break playback even when the complete file is valid.

Compare the origin server with the cached response if a deployment changed recently. An old media file under a new content-type header, or a stale manifest pointing to removed segments, can create intermittent failures across regions. Preserve the requested URL and response headers before invalidating caches.

For cross-origin use, distinguish ordinary playback from operations that require readable media data, such as drawing to a canvas and reading pixels. CORS requirements can differ by use. A video playing successfully does not prove that a later pixel read will be permitted.

Check the result of the playback request

The play method returns a promise in modern browsers. Handle rejection and keep a visible play control available. Autoplay rules, document state and user interaction can affect whether playback begins. Do not update the interface to playing before the operation actually succeeds.

try {
  await video.play();
  showPlayingState();
} catch (error) {
  showPlayButton();
  recordPlaybackError(error.name);
}

This code still needs application-specific handling, but it illustrates the boundary: the promise outcome controls the state. A user who pauses or leaves the page during loading can introduce another transition, so avoid stale callbacks overwriting the latest intent.

Diagnose a video that works only on the developer's laptop

Suppose a 4K video plays on a desktop but stutters on a phone. Both browsers return probably for a broad MP4 query. First inspect the actual codec profile and bitrate. Then serve a lower-resolution version encoded from the same source and compare playback on the same phone.

If the lower version plays smoothly, investigate decoding cost and network throughput rather than treating container support as the answer. A 60-frame-per-second stream can place different demands on the device from a 30-frame-per-second stream with the same dimensions.

Use MediaCapabilities.decodingInfo where supported with a configuration matching the real stream. Its supported, smooth and powerEfficient results provide additional hints. They still do not replace playback under the user's conditions, especially when network delivery or application workload is the bottleneck.

Keep a fallback source or adaptive rendition appropriate to your audience. Label formats by what they contain, and test the fallback selection itself. A fallback file that exists on disk but is never reached by the player's source-selection logic does not help users.

Do not forget the audio stream

A file can contain a supported video stream and an unsupported audio stream. It may display pictures without sound or fail as a whole depending on the player and format. Record both streams when comparing a working export with a failing one.

Also check muted state, volume, selected audio track and output routing before blaming decoding. A browser's autoplay policy can allow muted playback while restricting audible playback. That difference can make a video appear to work until the application enables sound.

Test captions and alternative audio where your product provides them. A technically successful video that loses captions after a source switch can still be unusable. Include these user-facing requirements in the playback acceptance test rather than focusing only on frame rendering.

Make the asset and cache strategy agree

Use versioned asset URLs when the bytes change, particularly for segmented media whose manifest refers to several files. Deploy the required segments before exposing the new manifest. Removing old segments too early can break viewers who loaded the previous manifest and are still playing.

Keep a sample asset for each supported encoding profile in your regression suite. A tiny generic video may not exercise the profile, colour depth or resolution that caused a real failure. Include one representative demanding asset and a lightweight fallback so the test can distinguish compatibility from performance.

Record the encoder settings with the asset. If a later pipeline update changes a default profile, you can then explain why the same filename extension started failing. File extension, encoding configuration and delivery configuration should all be reviewable in the deployment record.

Compare the delivered file with the encoder output

If the encoder output plays locally but the CDN copy does not, download the public asset and compare complete digests. A mismatch can reveal an incomplete upload, stale object or transformation. Confirm that you selected the same release and rendition before comparing. If the bytes match, investigate request handling, playback policy and browser decoding. This split prevents unnecessary re-encoding when the actual failure is in delivery or the page integration.

Frequently asked questions

Does probably mean every file of that type works?

No. It is a support hint for the supplied type information. The actual file can contain different streams, unsupported parameters or damaged data. Delivery and playback policy can fail independently. Use the hint to choose candidates, then attempt the real operation and handle its result.

Why does a downloaded file play but the website fails?

The desktop player may support more codecs, and the website adds network, origin and playback-policy conditions. Inspect the browser's requested bytes and error before changing the file. A login redirect or incorrect range response can explain the difference without any encoding defect.

Is hardware decoding guaranteed by codec support?

No. A browser can support decoding through software. Hardware availability depends on device, profile, resolution, drivers and browser configuration. Use detailed capability hints and actual performance measurements, and keep a lower-cost rendition for devices that cannot sustain the preferred stream.

Can the checker inspect a private media URL?

This checker queries local support for its listed types; it does not fetch an arbitrary media URL. Diagnose your private asset in its own authorised application context. Avoid sharing signed URLs or access tokens in a public support report; include a synthetic sample with the same encoding when possible.

What should I keep from a failed playback test?

Save the exact codec configuration, browser and device, media error, play-promise rejection if any, response status and relevant headers. Note whether playback began, whether audio worked and whether seeking failed. Those distinctions guide the next test much better than a single statement that MP4 is broken.

Sources and further reading

50 useful tools · ↑ ↓ to navigate · Enter to open · Esc to close