Summary
When downloading from Tidal, any track that Tidal has no lyrics for prints:
Failed to get lyrics for <id>: not all arguments converted during string formatting
The download itself succeeds — this is spurious noise — but it appears for every lyric-less track (instrumentals, classical, etc.).
Root cause
The Tidal lyrics endpoint returns 404 for tracks without lyrics. That hits this line in _api_request:
https://github.com/nathom/streamrip/blob/main/streamrip/client/tidal.py#L356
if resp.status == 404:
logger.warning("TIDAL: track not found", resp) # <-- bug
raise NonStreamableError("TIDAL: Track not found")
resp is passed as a positional logging arg, but the message string has no % placeholder. streamrip logs through rich.logging.RichHandler, which (unlike the stdlib default handler) re-raises the resulting formatting error instead of swallowing it via handleError. So a TypeError: not all arguments converted during string formatting propagates out of _api_request.
In the track-metadata path that exception is then caught here:
https://github.com/nathom/streamrip/blob/main/streamrip/client/tidal.py#L113-L128
elif media_type == "track":
try:
resp = await self._api_request(
f"tracks/{item_id!s}/lyrics", base="https://listen.tidal.com/v1"
)
...
except TypeError as e:
logger.warning(f"Failed to get lyrics for {item_id}: {e}")
...producing the user-visible warning. (The except TypeError is itself a hint that the real intent was to treat a missing-lyrics 404 as non-fatal — but it's catching it via the formatting-bug side effect rather than the actual NonStreamableError.)
Reproduction
Confirmed with a valid token (streamrip 2.2.0, git main, Python 3.13, macOS):
GET https://listen.tidal.com/v1/tracks/62300893/lyrics (Adele – "Hello") → 200 with lyrics (feature works fine).
GET .../tracks/135612114/lyrics (Bach – Cello Suite No. 1 Prelude, instrumental) → 404 → triggers the warning above.
Minimal demonstration that RichHandler re-raises the formatting error (stdlib default handler does not):
import logging
from rich.logging import RichHandler
logging.basicConfig(level="WARNING", format="%(message)s", handlers=[RichHandler()])
logging.getLogger("streamrip").warning("TIDAL: track not found", object())
# -> TypeError: not all arguments converted during string formatting
Suggested fix
Two small changes:
- Fix the malformed log call at
tidal.py:356, e.g.:
logger.debug("TIDAL: resource not found at %s/%s", base, path)
- Treat a missing-lyrics 404 as non-fatal explicitly instead of relying on the formatting bug, e.g. broaden the lyrics handler:
except (TypeError, NonStreamableError):
item["lyrics"] = ""
Happy to open a PR if useful.
Summary
When downloading from Tidal, any track that Tidal has no lyrics for prints:
The download itself succeeds — this is spurious noise — but it appears for every lyric-less track (instrumentals, classical, etc.).
Root cause
The Tidal lyrics endpoint returns
404for tracks without lyrics. That hits this line in_api_request:https://github.com/nathom/streamrip/blob/main/streamrip/client/tidal.py#L356
respis passed as a positional logging arg, but the message string has no%placeholder. streamrip logs throughrich.logging.RichHandler, which (unlike the stdlib default handler) re-raises the resulting formatting error instead of swallowing it viahandleError. So aTypeError: not all arguments converted during string formattingpropagates out of_api_request.In the track-metadata path that exception is then caught here:
https://github.com/nathom/streamrip/blob/main/streamrip/client/tidal.py#L113-L128
...producing the user-visible warning. (The
except TypeErroris itself a hint that the real intent was to treat a missing-lyrics 404 as non-fatal — but it's catching it via the formatting-bug side effect rather than the actualNonStreamableError.)Reproduction
Confirmed with a valid token (streamrip 2.2.0, git main, Python 3.13, macOS):
GET https://listen.tidal.com/v1/tracks/62300893/lyrics(Adele – "Hello") → 200 with lyrics (feature works fine).GET .../tracks/135612114/lyrics(Bach – Cello Suite No. 1 Prelude, instrumental) → 404 → triggers the warning above.Minimal demonstration that
RichHandlerre-raises the formatting error (stdlib default handler does not):Suggested fix
Two small changes:
tidal.py:356, e.g.:Happy to open a PR if useful.