How to Validate a DASH MPD Manifest
You validate a DASH MPD by checking two separate layers: is the XML itself well-formed and schema-conformant per ISO/IEC 23009-1, and do the attributes a real player depends on describe a stream that will actually play. Passing the first layer only proves the file parses; it says nothing about whether segments resolve or whether a live stream keeps its clock in sync.
Most manifests that "validate" against a generic XML schema still fail in players because the schema check does not catch a wrong availabilityStartTime, a SegmentTemplate whose $Number$ pattern never matches a segment the origin actually serves, or a ContentProtection block missing the PSSH a specific DRM client needs. Treat schema validation as the first filter, not the whole job.
The rest of this guide walks the checks in the order that catches the most common breakage first: structure, then addressing, then protection, then the HTTP behaviour underneath the XML.
What does "valid" actually mean for an MPD?
An MPD is valid at the XML level when it parses without errors and conforms to the MPD schema defined in ISO/IEC 23009-1 Annex A. That means correct namespaces (xmlns="urn:mpeg:dash:schema:mpd:2011" at minimum), correctly nested Period/AdaptationSet/Representation elements, and attribute values in the types the schema expects (durations as ISO 8601, e.g. PT6S, not "6" or "6 seconds").
Schema-valid is not the same as playable. A manifest can be perfectly well-formed and still be unusable because it points at segments that 404, declares a live type without a working clock-sync scheme, or lists a codec string a target device cannot decode. Validation for a real launch needs both the structural pass and the functional checks below.
Are the mandatory top-level attributes present and consistent?
Every MPD needs a type attribute, either "static" for VOD or "dynamic" for live. A dynamic MPD must also carry availabilityStartTime, the wall-clock instant Period 0 became available; every segment's availability window is calculated relative to this timestamp, so a wrong value shifts the whole live edge.
minBufferTime tells the player the minimum buffer the encoding was designed to allow smooth playback; it should reflect the actual encode, not a copy-pasted default. For dynamic manifests, also check minimumUpdatePeriod (how often the player should refetch the MPD) and timeShiftBufferDepth (how far back the player can seek). A missing minimumUpdatePeriod on a live stream means players will not know to refresh the manifest at all.
profiles should declare the DASH profile actually being served, such as urn:mpeg:dash:profile:isoff-live:2011 for fragmented-MP4 live. A profile mismatch is not always fatal, but it is a strong sign the manifest was generated by a generic packager preset rather than tuned for the target players.
Does the segment addressing scheme actually resolve?
DASH offers three addressing modes and the MPD must use one consistently within a Representation: SegmentBase (one file, addressed with byte ranges via an index), SegmentList (an explicit list of segment URLs), and SegmentTemplate, which builds URLs from a pattern using $Number$ or $Time$ substitution.
With $Number$-based SegmentTemplate, check that startNumber matches the first segment actually present on the origin and that the duration attribute (or a SegmentTimeline's set of S elements) matches real segment lengths. A one-segment-off startNumber is the single most common cause of a manifest that validates structurally but returns 404 on the very first fetch.
With SegmentTimeline, each S element's d (duration) and r (repeat count) must sum to a timeline that matches what the packager actually produced; a drifted timeline causes players to request a $Time$ value that was never generated. Fetch a sample of the computed segment URLs directly with curl and confirm each one returns 200 with the expected content type before trusting the manifest.
Does ContentProtection describe a DRM path that will actually work?
A ContentProtection element identifies a DRM system by schemeIdUri, typically a UUID such as edef8ba9-79d6-4ace-a3c8-27dcd51d21ed for Widevine or 9a04f079-9840-4286-ab92-e65be0885f95 for PlayReady. Each system-specific block should carry a cenc:pssh element containing the base64-encoded PSSH box that initializes the CDM.
A common failure is a PSSH generated for the wrong key ID, or a ContentProtection block present in the AdaptationSet but missing from the Representations that actually reference encrypted segments, so some renditions play while others fail to decrypt. Confirm the key ID embedded in the PSSH matches the key used to encrypt the referenced segments, not just that a PSSH is present.
What HTTP-level checks matter beyond the XML itself?
The manifest response itself needs a sane Content-Type (application/dash+xml) and, for live, short or no caching (a long max-age on a dynamic MPD means players keep polling a stale manifest and miss new segments). Check Cache-Control and any CDN-added headers separately from the XML.
CORS matters whenever the page playing the stream is on a different origin from the manifest or segments: without an Access-Control-Allow-Origin header covering the player's origin, browser-based players will fail to fetch segments even though curl from a terminal succeeds. Redirects (301/302) on manifest or segment URLs are legal but add latency and some low-level DASH clients do not follow them for every segment request, so prefer serving the final URL directly.
Where do validators give false confidence?
A schema-only validator will pass an MPD with an availabilityStartTime years in the future or a codecs string that names a profile no shipping decoder supports, because both are syntactically valid strings. Always cross-check codecs (e.g. avc1.640028, hvc1.1.6.L93.90) against the actual capability of the devices you target.
Conversely, some strict validators reject manifests that real players accept happily, such as vendor-specific extension attributes prefixed with a non-standard namespace. Treat a validator failure on an unrecognized attribute as informational, and confirm actual player behaviour before treating it as a launch blocker.
Step by step
- Fetch the MPD and confirm it returns HTTP 200 with Content-Type application/dash+xml.
- Run it through an XML/schema validator to catch malformed structure before anything else.
- Check type, availabilityStartTime, minBufferTime, and (for live) minimumUpdatePeriod and timeShiftBufferDepth.
- Resolve a sample of SegmentTemplate or SegmentList URLs by hand and confirm each returns the expected segment.
- If ContentProtection is present, verify the PSSH key ID matches the encryption key used on the referenced segments.
- Check response headers on the manifest and segments for correct Cache-Control and CORS.
- Load the manifest in at least one real player (not just a validator) and confirm it starts and holds a live edge if dynamic.
Run it yourself
Free, no sign-up, and every finding links to an explainer.
Frequently asked questions
- Can an MPD be schema-valid but still unplayable?
- Yes. Schema validation only confirms the XML structure and attribute types are correct. It does not check that segment URLs resolve, that availabilityStartTime is accurate, or that the codecs string matches a decoder any real device supports.
- Do I need a separate validator for live versus VOD manifests?
- The XML schema is the same, but live (type="dynamic") manifests need extra checks a VOD validator will not perform: availabilityStartTime accuracy, minimumUpdatePeriod, timeShiftBufferDepth, and clock synchronisation via UTCTiming.
- Why does my MPD validate but segments return 404?
- The most common cause is a SegmentTemplate startNumber that does not match the first segment actually present on the origin, or a SegmentTimeline whose durations have drifted from what the packager produced. Resolve a few segment URLs by hand with curl to confirm.
- Is a missing ContentProtection block always an error?
- No. It is only required when the content is actually encrypted. An unencrypted (clear) stream correctly has no ContentProtection element at all; adding one to clear content will make DRM-aware players attempt and fail a license request.
- What is the fastest manual check before running a full validator?
- Fetch the MPD with curl, confirm it is well-formed XML, read off the type and profiles attributes, then resolve one segment URL from the addressing scheme by hand. That single round trip catches most real-world breakage without any tooling.
DASH findings, explained
Read next
Last reviewed 2026-09-16.