Skip to content

Spotify API Update Prevents SpotDL from working. #2621

@Numberedwayne

Description

@Numberedwayne

System OS

Other

Python Version

3.10 (CPython)

Install Source

pip / PyPi

Install version / commit hash

4.4.3

Expected Behavior vs Actual Behavior

Spotify API changes prevent SpotDL from functioning.

Refer here: [https://developer.spotify.com/documentation/web-api/references/changes/february-2026]

Steps to reproduce - Ensure to include actual links!

  1. Try to download a song using the query or playlist url.

Traceback

root@NumberedOrgCore:~# spotdl download "https://open.spotify.com/playlist/1KpkWMFG1PMOeNUTG988vD"   --format flac   --output "/mnt/Storage01/Media/Mu
sic/{artist}/{album}/{title}"   --lyrics genius musixmatch   --user-auth   --headless
Processing query: https://open.spotify.com/playlist/1KpkWMFG1PMOeNUTG988vD
HTTP Error for GET to https://api.spotify.com/v1/playlists/1KpkWMFG1PMOeNUTG988vD/tracks with Params: {'limit': 100, 'offset': 0, 'fields': None,
'market': None, 'additional_types': 'track,episode'} returned 403 due to Forbidden

An error occurred
╭──────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────╮
│ /usr/local/lib/python3.11/dist-packages/spotipy/client.py:274 in _internal_call                                                                    │
│                                                                                                                                                    │
│    271 │   │   │   │   timeout=self.requests_timeout, **args                                                                                       │
│    272 │   │   │   )                                                                                                                               │
│    273 │   │   │                                                                                                                                   │
│ ❱  274 │   │   │   response.raise_for_status()                                                                                                     │
│    275 │   │   │   results = response.json()                                                                                                       │
│    276 │   │   except requests.exceptions.HTTPError as http_error:                                                                                 │
│    277 │   │   │   response = http_error.response                                                                                                  │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/requests/models.py:1026 in raise_for_status                                                                │
│                                                                                                                                                    │
│   1023 │   │   │   )                                                                                                                               │
│   1024 │   │                                                                                                                                       │
│   1025 │   │   if http_error_msg:                                                                                                                  │
│ ❱ 1026 │   │   │   raise HTTPError(http_error_msg, response=self)                                                                                  │
│   1027 │                                                                                                                                           │
│   1028 │   def close(self):                                                                                                                        │
│   1029 │   │   """Releases the connection back to the pool. Once this method has been                                                              │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
HTTPError: 403 Client Error: Forbidden for url:
https://api.spotify.com/v1/playlists/1KpkWMFG1PMOeNUTG988vD/tracks?limit=100&offset=0&additional_types=track%2Cepisode

During handling of the above exception, another exception occurred:

╭──────────────────────────────────────────────────────── Traceback (most recent call last) ─────────────────────────────────────────────────────────╮
│ /usr/local/lib/python3.11/dist-packages/spotdl/console/entry_point.py:160 in entry_point                                                           │
│                                                                                                                                                    │
│   157 │   try:                                                                                                                                     │
│   158 │   │   # Pick the operation to perform                                                                                                      │
│   159 │   │   # based on the name and run it!                                                                                                      │
│ ❱ 160 │   │   OPERATIONS[arguments.operation](                                                                                                     │
│   161 │   │   │   query=arguments.query,                                                                                                           │
│   162 │   │   │   downloader=downloader,                                                                                                           │
│   163 │   │   )                                                                                                                                    │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotdl/console/download.py:25 in download                                                                  │
│                                                                                                                                                    │
│   22 │   """                                                                                                                                       │
│   23 │                                                                                                                                             │
│   24 │   # Parse the query                                                                                                                         │
│ ❱ 25 │   songs = get_simple_songs(                                                                                                                 │
│   26 │   │   query,                                                                                                                                │
│   27 │   │   use_ytm_data=downloader.settings["ytm_data"],                                                                                         │
│   28 │   │   playlist_numbering=downloader.settings["playlist_numbering"],                                                                         │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotdl/utils/search.py:264 in get_simple_songs                                                             │
│                                                                                                                                                    │
│   261 │   │   │   )                                                                                                                                │
│   262 │   │   │   songs.extend(full_lists)                                                                                                         │
│   263 │   │   elif "open.spotify.com" in request and "playlist" in request:                                                                        │
│ ❱ 264 │   │   │   lists.append(Playlist.from_url(request, fetch_songs=False))                                                                      │
│   265 │   │   elif "open.spotify.com" in request and "album" in request:                                                                           │
│   266 │   │   │   lists.append(Album.from_url(request, fetch_songs=False))                                                                         │
│   267 │   │   elif "open.spotify.com" in request and "artist" in request:                                                                          │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotdl/types/song.py:306 in from_url                                                                       │
│                                                                                                                                                    │
│   303 │   │   - The SongList object.                                                                                                               │
│   304 │   │   """                                                                                                                                  │
│   305 │   │                                                                                                                                        │
│ ❱ 306 │   │   metadata, songs = cls.get_metadata(url)                                                                                              │
│   307 │   │   urls = [song.url for song in songs]                                                                                                  │
│   308 │   │                                                                                                                                        │
│   309 │   │   if fetch_songs:                                                                                                                      │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotdl/types/playlist.py:72 in get_metadata                                                                │
│                                                                                                                                                    │
│    69 │   │   │   ),                                                                                                                               │
│    70 │   │   }                                                                                                                                    │
│    71 │   │                                                                                                                                        │
│ ❱  72 │   │   playlist_response = spotify_client.playlist_items(url)                                                                               │
│    73 │   │   if playlist_response is None:                                                                                                        │
│    74 │   │   │   raise PlaylistError(f"Wrong playlist id: {url}")                                                                                 │
│    75                                                                                                                                              │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotipy/client.py:724 in playlist_items                                                                    │
│                                                                                                                                                    │
│    721 │   │   │   │   │   │   │   │   │    valid types are: track and episode                                                                     │
│    722 │   │   """                                                                                                                                 │
│    723 │   │   plid = self._get_id("playlist", playlist_id)                                                                                        │
│ ❱  724 │   │   return self._get(                                                                                                                   │
│    725 │   │   │   f"playlists/{plid}/tracks",                                                                                                     │
│    726 │   │   │   limit=limit,                                                                                                                    │
│    727 │   │   │   offset=offset,                                                                                                                  │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotdl/utils/spotify.py:195 in _get                                                                        │
│                                                                                                                                                    │
│   192 │   │   retries = self.max_retries  # type: ignore # pylint: disable=E1101                                                                   │
│   193 │   │   while response is None:                                                                                                              │
│   194 │   │   │   try:                                                                                                                             │
│ ❱ 195 │   │   │   │   response = self._internal_call("GET", url, payload, kwargs)                                                                  │
│   196 │   │   │   except (requests.exceptions.Timeout, requests.ConnectionError) as exc:                                                           │
│   197 │   │   │   │   retries -= 1                                                                                                                 │
│   198 │   │   │   │   if retries <= 0:                                                                                                             │
│                                                                                                                                                    │
│ /usr/local/lib/python3.11/dist-packages/spotipy/client.py:294 in _internal_call                                                                    │
│                                                                                                                                                    │
│    291 │   │   │   logger.error(f"HTTP Error for {method} to {url} with Params: "                                                                  │
│    292 │   │   │   │   │   │    f"{args.get('params')} returned {response.status_code} due to                                                      │
│        {msg}")                                                                                                                                     │
│    293 │   │   │                                                                                                                                   │
│ ❱  294 │   │   │   raise SpotifyException(                                                                                                         │
│    295 │   │   │   │   response.status_code,                                                                                                       │
│    296 │   │   │   │   -1,                                                                                                                         │
│    297 │   │   │   │   f"{response.url}:\n {msg}",                                                                                                 │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
SpotifyException: http status: 403, code: -1 -
https://api.spotify.com/v1/playlists/1KpkWMFG1PMOeNUTG988vD/tracks?limit=100&offset=0&additional_types=track%2Cepisode:
 Forbidden, reason: None
root@NumberedOrgCore:~#

Other details

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugUnexpected problem or unintended behavior that needs to be fixed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions