Repository navigation
Manifest decoding has suddenly broken #396
Copy link
Copy link
Closed
Labels
Description
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.
Reactions are currently unavailable
Activity
ChrisIossa commentedon Jan 15, 2026
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
chore(media): Don't suppress original exception in ManifestDecodeError
blacklight commentedon Jan 15, 2026
Ok I've found the root cause. It was quite a ride because
python-tidalswallows 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@groupshould be numeric, sompegdashis right to expect it to be numeric.So the "fix" consists in simply skipping the MPD manifest parsing, since
mopidy-tidalsimply writes it to disk and passes it to the playback layer anyway.TL;DR
Temporarily fix while the PRs are reviewed:
(cc @tehkillerbee)
tehkillerbee commentedon Jan 15, 2026
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.
blacklight commentedon Jan 16, 2026
@tehkillerbee
Yesterday I almost thought of opening a PR on mpegdash to be a bit more liberal on how
AdaptationSet@groupis parsed (it currently does a directint()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".
tehkillerbee commentedon Jan 18, 2026
@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?
blacklight commentedon Jan 18, 2026
This is the MPEG-DASH spec.
Page 32:
Perhaps it's not explicitly mentioned that it should be an integer, but the "zero/non-zero" talk seem to imply it quite clearly.
Let's try and bring it to the
mpegdashdevs, 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
mpegdashfork indefinitely doesn't exactly excite me)blacklight commentedon Jan 18, 2026
(I will actually reopen this issue, the underlying problem is still there, it's just fixed with a workaround on mopidy-tidal)
blacklight commentedon Jan 18, 2026
@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 asmpegdash-tidaland replace the dependency here.CURRENT WORKAROUNDUntil we figure out what's the best way forward, anyone who experiences this issue can installmpegdashfrom my branch: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 mpegdashshould now deploy the fix.Thanks to the mpegdash folks for the swift action!
@tehkillerbee I have bumped mpegdash to 0.4.1 here.
chore(deps): Bump mpegdash version to 0.4.1