Spotify API changes prevent SpotDL from functioning.
Refer here: [https://developer.spotify.com/documentation/web-api/references/changes/february-2026]
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:~#
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!
Traceback
Other details
No response