spotipy: "401 error: The access token expired" when using SpotifyClientCredentials

I am creating my Spotipy object like this, after reading this code snippet:

scc = SpotifyClientCredentials(client_id = SPOTIPY_CLIENT_ID,
                                   client_secret = SPOTIPY_CLIENT_SECRET)
sp = spotipy.Spotify(client_credentials_manager = scc)

However, after a number of queries, I obtain the following error:

http status:401                                                                 
Traceback (most recent call last):                                              
  File "retriever2.py", line 114, in <module>                                   
    store_songs(terms, dbfile, total_number)                                    
  File "retriever2.py", line 97, in store_songs                                 
    songs = get_songs(sp, playlist)                                             
  File "retriever2.py", line 36, in get_songs                                   
    track_results = sp.next(track_results)                                      
  File "/home/chema/.local/lib/python2.7/site-packages/spotipy/client.py", line 172, in next
    return self._get(result['next'])                                            
  File "/home/chema/.local/lib/python2.7/site-packages/spotipy/client.py", line 123, in _get
    return self._internal_call('GET', url, payload, kwargs)                     
  File "/home/chema/.local/lib/python2.7/site-packages/spotipy/client.py", line 104, in _internal_call
    -1, '%s:\n %s' % (r.url, r.json()['error']['message']))                     
spotipy.client.SpotifyException: http status: 401, code:-1 - https://api.spotify.com/v1/users/1248788010/playlists/4wEVX1M28mBIpiHttM6PrP/tracks?offset=100&limit=100:
 The access token expired      

I was under the impression that SpotifyClientCredentials was used to update the access token accordingly. Right now, I have my queries inside a try - except block and I refresh it manually (I basically recreate the sp object every time I get an exception). Am I using this correctly or is there any other way?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 17 (2 by maintainers)

Most upvoted comments

@ritiek Now it works, thanks for the help.

Great, thank you! You should have received the invite from @plamere

The goal is to automate RTD + PyPi deployments from a single account, but if needed we can still request it later

Sure, thanks! That would be very nice.

@Biggerandreas You don’t need to feed your refreshed token to Main.spot(). Main.refresh_token() automatically take cares of that with self.sp = spotipy.Spotify(auth=new_token['access_token']).

You could just reduce your except block to:

except spotipy.client.SpotifyException:
	main.refresh_token()
	print("Got an exception ")

When your token expires (after 1 hour), your code will raise an exception spotipy.client.SpotifyException which will cause Main.refresh_token() to execute which should refresh your instance of spotipy.Spotify() with your newly refreshed token, so the script should keep working fine.

In any case, shouldn’t spotipy handle this internally?

@rinze Yep, it would nice to have an optional argument to spotipy.Spotify(auto_refresh=True) which would automatically refresh token once it expires. I don’t see any active development on spotipy, so can’t say how long before anything like this happens.

@Biggerandreas Actually, there are couple of things you need to fix with your code. I’ll try to explain my best. 😃


  • You are calling Main.refresh_token() unnecessarily at multiple places, which would slow down your script. We only need to call it when a spotipy.client.SpotifyException is raised. You should remove calling it from any other place.
  • As spotipy.client.SpotifyException is raised when the token expires, we don’t need to check it again in Main.refresh_token(). So, we can reduce Main.refresh_token() to something below:
    def refresh_token(self):
        cached_token = self.spo.get_cached_token()
        refreshed_token = cached_token['refresh_token']
        new_token = self.spo.refresh_access_token(refreshed_token)
        # also we need to specifically pass `auth=new_token['access_token']`
        self.sp = spotipy.Spotify(auth=new_token['access_token'])
        return new_token

You could then just call main.refresh_token() in your except block which should refresh token.

  • In your main loop, you should place main.get_song() under try block otherwise we cannot catch any exception it raises (in our case, we want to catch spotipy.client.SpotifyException).
  • You are also trying to subtract 2 different times in str which is not possible. Consider:
import time
time_started = time.strftime("%Y-%m-%d %H:%M:%S")
current_time = time.strftime("%Y-%m-%d %H:%M:%S")
print(time_started - current_time)
Traceback (most recent call last):
  File "timi.py", line 4, in <module>
    print(time_started - current_time)
TypeError: unsupported operand type(s) for -: 'str' and 'str'

As a workaround, we can convert them to datetime.datetime objects and then subtract them:

from datetime import datetime
import time
fmt = "%Y-%m-d %H:%M:%S"
time_started = time.strftime(fmt)
current_time = time.strftime(fmt)
# also i think you meant `current_time - time_started` and not other way round
print(datetime.strptime(current_time, fmt) - datetime.strptime(time_started, fmt))

That should clear most stuff. Let me know if anything is still not right. 😃

@Biggerandreas That should not be happening, I’ve been using something similar without problems. Do you mind sharing relevant code from your script here? (removing any credentials of course)

@Biggerandreas You can use something like this to catch exception raised when the token expires:

try:
    do_something()
except spotipy.client.SpotifyException:
    # re-authenticate when token expires
    token = ...
    sp = spotipy.Spotify(auth=token)
    do_something()