Skip to content

Manifest decoding has suddenly broken #396

Closed

Description

@blacklight

This is something that literally happened in the past couple of hours - playback was working fine until 2-3 hours ago:

INFO     2026-01-15 17:06:26,971 [1036280:TidalBackend-12] mopidy_tidal.playback
  TIDAL uri: tidal:track:3509189:1381853:1381859
ERROR    2026-01-15 17:06:27,274 [1036280:Core-14] mopidy.core.playback
  TidalBackend backend caused an exception.
Traceback (most recent call last):
  File "/home/blacklight/.local/lib/python3.14/site-packages/tidalapi/media.py", line 770, in from_mpd
    return DashInfo(mpd_manifest)
  File "/home/blacklight/.local/lib/python3.14/site-packages/tidalapi/media.py", line 775, in __init__
    mpd = MPEGDASHParser.parse(
        mpd_xml.split("<?xml version='1.0' encoding='UTF-8'?>")[1]
    )
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/parser.py", line 26, in parse
    return parse_child_nodes(xml_root_node, 'MPD', MPEGDASH)[0]
           ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/utils.py", line 25, in parse_child_nodes
    node.parse(elem)
    ~~~~~~~~~~^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/nodes.py", line 782, in parse
    self.periods = parse_child_nodes(xmlnode, 'Period', Period)
                   ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/utils.py", line 25, in parse_child_nodes
    node.parse(elem)
    ~~~~~~~~~~^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/nodes.py", line 718, in parse
    self.adaptation_sets = parse_child_nodes(xmlnode, 'AdaptationSet', AdaptationSet)
                           ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/utils.py", line 25, in parse_child_nodes
    node.parse(elem)
    ~~~~~~~~~~^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/nodes.py", line 602, in parse
    self.group = parse_attr_value(xmlnode, 'group', int)
                 ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/mpegdash/utils.py", line 47, in parse_attr_value
    return value_type(attr_val)
ValueError: invalid literal for int() with base 10: 'main'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/home/blacklight/.local/lib/python3.14/site-packages/mopidy/core/playback.py", line 352, in _change
    if not backend.playback.change_track(pending_tl_track.track).get():
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/pykka/_threading.py", line 80, in get
    raise exc_value
  File "/home/blacklight/.local/lib/python3.14/site-packages/pykka/_actor.py", line 260, in _actor_loop_running
    response = self._handle_receive(envelope.message)
  File "/home/blacklight/.local/lib/python3.14/site-packages/pykka/_actor.py", line 377, in _handle_receive
    return callee(*message.args, **message.kwargs)
  File "/home/blacklight/.local/lib/python3.14/site-packages/mopidy/backend.py", line 331, in change_track
    uri = self.translate_uri(track.uri)
  File "/home/blacklight/.local/lib/python3.14/site-packages/mopidy_tidal/login_hack.py", line 306, in wrapper
    return fn(obj, *args, **kwargs)
  File "/home/blacklight/.local/lib/python3.14/site-packages/mopidy_tidal/playback.py", line 41, in translate_uri
    manifest = stream.get_stream_manifest()
  File "/home/blacklight/.local/lib/python3.14/site-packages/tidalapi/media.py", line 606, in get_stream_manifest
    return StreamManifest(self)
  File "/home/blacklight/.local/lib/python3.14/site-packages/tidalapi/media.py", line 644, in __init__
    self.dash_info = DashInfo.from_mpd(stream.get_manifest_data())
                     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/blacklight/.local/lib/python3.14/site-packages/tidalapi/media.py", line 772, in from_mpd
    raise ManifestDecodeError
tidalapi.exceptions.ManifestDecodeError
WARNING  2026-01-15 17:06:27,277 [1036280:Core-14] mopidy.core.tracklist
  Track is not playable: tidal:track:3509189:1381853:1381859

I can start taking a look if it's something new - just wanted to double check if this is also broken for other users.

Activity

  1. added theissue type on Jan 15, 2026
  2. ChrisIossa commented on Jan 15, 2026

    @ChrisIossa

    I can start taking a look if it's something new - just wanted to double check if this is also broken for other users.

    I am also experiencing this issue, via Mopidy-Tidal, and can also confirm that it came on suddenly. Playback worked around 13:30 UTC and I first noticed it was broken around 16:00 UTC

  3. blacklight commented on Jan 15, 2026

    @blacklight
    CollaboratorAuthor

    Ok I've found the root cause. It was quite a ride because python-tidal swallows all media manifest errors, so I had to manually place breakpoints around to understand what was going on. This should be amended here.

    The main fix has been applied to mopidy-tidal instead: EbbLabs/mopidy-tidal#216

    Long story short, the TIDAL API has started sending non-numeric group IDs (like main) in the media manifest inside the MPD wrapper.

    That breaks mpegdash, because it expects groups to be numeric.

    IMHO this is quite a big fluke on the TIDAL side. The MPEG-DASH (ISO/IEC 23009-1) specification says (page 32) that AdaptationSet@group should be numeric, so mpegdash is right to expect it to be numeric.

    So the "fix" consists in simply skipping the MPD manifest parsing, since mopidy-tidal simply writes it to disk and passes it to the playback layer anyway.

    TL;DR

    Temporarily fix while the PRs are reviewed:

    pip install -U "git+https://github.com/blacklight/python-tidal.git@fix/updated-handling-of-media-manifest#egg=Mopidy-Tidal"
    # Optional but advised, to ensure that any further manifest errors
    # are easy to debug
    pip install -U "git+https://github.com/blacklight/python-tidal.git@396/handle-manifest-decode-errors#egg=tidalapi"
    

    (cc @tehkillerbee)

  4. tehkillerbee commented on Jan 15, 2026

    @tehkillerbee
    Collaborator

    Oh dear... Good detective work!

    For now the only real solution is to avoid using the MPD manifest parsing. For mopidy-tidal this is no problem of course. But for other 3rdparty libraries relying on tidalapi, this will be an issue.

  5. blacklight commented on Jan 16, 2026

    @blacklight
    CollaboratorAuthor

    @tehkillerbee

    For mopidy-tidal this is no problem of course. But for other 3rdparty libraries relying on tidalapi, this will be an issue.

    Yesterday I almost thought of opening a PR on mpegdash to be a bit more liberal on how AdaptationSet@group is parsed (it currently does a direct int() because it expects it to always be a number). Perhaps even printing a warning rather than failing hard.

    But of course I'd expect some push back along the lines of "the MPEG-DASH specification has been around for more than two decaes, we won't change our implementation just because some creative dev at Tidal decided to break it".

  6. tehkillerbee commented on Jan 18, 2026

    @tehkillerbee
    Collaborator

    @blacklight We might need to fork mpegdash and/or add the necessary sources to this repo and fix it in that way.

    If tidal actually breaks spec, it probably doesn't make sense to fix it in mpegdash, if the Tidal devs decided to not follow specifications. But on the other hand, it should be pretty easy to make a workaround / warning and allow it to parse.

    I haven't studied the spec yet, so I can't say for sure if it is always meant to be a number. Do you have a source for this?

  7. blacklight commented on Jan 18, 2026

    @blacklight
    CollaboratorAuthor

    I haven't studied the spec yet, so I can't say for sure if it is always meant to be a number. Do you have a source for this?

    This is the MPEG-DASH spec.

    Page 32:

    Adaptation Sets may be further arranged into groups using the @group attribute. The semantics of this grouping is that the media content within one Period is represented by:

    1. either one Representation from group 0, if present,
    2. or the combination of at most one Representation from each non-zero group.
      If the AdaptationSet@group attribute is not present then all Representations in this Adaptation Set are assigned to a non-zero group specific to this Adaptation Set

    Perhaps it's not explicitly mentioned that it should be an integer, but the "zero/non-zero" talk seem to imply it quite clearly.

    If tidal actually breaks spec, it probably doesn't make sense to fix it in mpegdash, if the Tidal devs decided to not follow specifications. But on the other hand, it should be pretty easy to make a workaround / warning and allow it to parse.

    Let's try and bring it to the mpegdash devs, they definitely have a clearer idea than me about the specs.

    But if they come back with "sorry, these are the specs" we'll probably have to think of an alternative approach (and maintaining an mpegdash fork indefinitely doesn't exactly excite me)

  8. blacklight commented on Jan 18, 2026

    @blacklight
    CollaboratorAuthor

    (I will actually reopen this issue, the underlying problem is still there, it's just fixed with a workaround on mopidy-tidal)

  9. blacklight commented on Jan 18, 2026

    @blacklight
    CollaboratorAuthor

    @tehkillerbee ok, you know what...mpegdash hasn't seen any commits in two years, and the specs are unlikely to change. I don't think it's going to be such a big deal to fork it.

    For now I have pushed a PR that simply implements a fallback cast.

    Let's see if someone reaches out and what they say. Ideally it's merged upstream and we don't need a fork.

    If we do (let's give them 1-2 weeks to reach back), then I'm ok to publish the fork to PyPI as mpegdash-tidal and replace the dependency here.

    CURRENT WORKAROUND

    Until we figure out what's the best way forward, anyone who experiences this issue can install mpegdash from my branch:

    pip install -U "git+https://github.com/blacklight/python-mpegdash.git@workaround-for-broken-tidal-manifests#egg=mpegdash"
    

    EDIT

    The PR has been merged! 🎉

    No need for forks, it'll be included in the next release of mpegdash 🙂

    EDIT 2

    python-mpegdash 0.4.1 has been released with the fix 🎉

    No more need for the previous workaround, a pip install -U mpegdash should now deploy the fix.

    Thanks to the mpegdash folks for the swift action!

    @tehkillerbee I have bumped mpegdash to 0.4.1 here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions