subhra74/xdm · error

Encrypted manifest

Error message

Encrypted manifest

What it means

Parse performs a SelectNodes/SelectSingleNode search for any ContentProtection element in the manifest. ContentProtection signals DRM (Widevine/PlayReady etc.) encryption, so its presence means the media cannot be downloaded as plaintext. The parser throws immediately to refuse DRM-protected content.

Solutions

  1. Use a non-DRM source for the content; this library cannot and should not decrypt DRM streams.
  2. Check for an unencrypted rendition of the same content (some services expose clear-key/free variants).
  3. Catch this exception and surface a clear 'content is DRM protected' message instead of a generic failure.
  4. If you own the content, remove ContentProtection from the test manifest or serve a clear variant for development.
Defensive patterns

Strategy: validation

Validate before calling

var body = await http.GetStringAsync(manifestUrl);
if (body.Contains("ContentProtection"))
    throw new Exception("Manifest is DRM-protected (ContentProtection present)");

Try / catch

try { return MpdParser.Parse(url, null); }
catch (Exception ex) when (ex.Message == "Encrypted manifest")
{ throw new DrmProtectedException("Cannot download DRM-protected content", ex); }

Prevention

When it happens

Trigger: Parsing an MPD manifest that contains <ContentProtection> elements under AdaptationSet/Representation — i.e. any DRM-protected (encrypted) DASH stream.

Common situations: Streaming platforms using Widevine/PlayReady DRM (Netflix-like services, paid VOD); manifests from services where the free tier is unencrypted but the premium tier is DRM-locked; test URLs from DRM SDK demos.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of subhra74/xdm@1ca5a25aae (2026-09-13). Data as JSON: /api/errors/3748e419eae66e49. Report an issue: GitHub.

Appendix: source

Thrown at app/XDM/XDM.Core/MediaParser/Dash/MpdParser.cs:37

            new Regex(@"\$(RepresentationID|Time|Time%0(?<time_digits>[\d]+)(?<time_dx>[dx])?|Number|Number%0(?<num_digits>[\d]+)(?<num_dx>[dx])?|Bandwidth)\$");
        //@"\$(RepresentationID|Time|Time(%0([\d]+)([dx])?)?|Number|Number(%0([\d]+)([dx])?)?|Bandwidth)\$");
        public static IList<IList<KeyValuePair<Representation?, Representation?>>> Parse(
            string[] manifestLines,
            string playlistUrl)
        {
            using var memstream = new MemoryStream(Encoding.UTF8.GetBytes(string.Join("\n", manifestLines)));
            var xmldoc = new XmlDocument();
            xmldoc.Load(new XmlTextReader(memstream)
            {
                Namespaces = false
            });

            if (xmldoc.DocumentElement?.Name != "MPD")
                throw new Exception("Missing MPD start tag: " + xmldoc.DocumentElement.Name);
            if (xmldoc.DocumentElement.Attributes["type"]?.Value == "dynamic")
                throw new Exception("Manifest type dynamic is not supported");
            if (xmldoc.DocumentElement.SelectSingleNode("descendant::ContentProtection") != null)
                throw new Exception("Encrypted manifest");

            var mediaList = new List<IList<KeyValuePair<Representation?, Representation?>>>();

            var mediaPresentationDuration =
                DashUtil.ParseXsDuration(xmldoc.DocumentElement.Attributes["mediaPresentationDuration"]?.Value ?? "0");
            var baseUrl = new Uri(playlistUrl);
            var baseUrlNodeRoot = xmldoc.DocumentElement.SelectSingleNode("child::BaseURL");
            if (baseUrlNodeRoot != null)
            {
                baseUrl = UrlResolver.Resolve(baseUrl, baseUrlNodeRoot.InnerText);
            }

            var periods = xmldoc.DocumentElement.SelectNodes("child::Period");
            if (periods == null || periods.Count < 1) throw new Exception("No period found!");
            if (periods.Count > 1)
            {
                var periodDurations = CalculatePeriodDurationsIfMissing(periods, mediaPresentationDuration);
                for (var i = 0; i < periods.Count; i++)

View on GitHub (pinned to 1ca5a25aae)