[BUG] case of automatic token refresh failure
Is this issue already tracked somewhere, or is this a new report?
- [X] I've reviewed existing issues and couldn't find a duplicate for this problem.
Current Behavior
My EDL token is not getting refreshed.
import earthaccess
auth = earthaccess.login()
earthaccess.search_datasets(instrument="oci")
---------------------------------------------------------------------------
HTTPError Traceback (most recent call last)
File [/srv/conda/envs/notebook/lib/python3.10/site-packages/earthaccess/search.py:86](https://oss.oel.smce.nasa.gov/srv/conda/envs/notebook/lib/python3.10/site-packages/earthaccess/search.py#line=85), in DataCollections.hits(self)
85 try:
---> 86 response.raise_for_status()
87 except requests.exceptions.HTTPError as ex:
File [/srv/conda/envs/notebook/lib/python3.10/site-packages/requests/models.py:1021](https://oss.oel.smce.nasa.gov/srv/conda/envs/notebook/lib/python3.10/site-packages/requests/models.py#line=1020), in Response.raise_for_status(self)
1020 if http_error_msg:
-> 1021 raise HTTPError(http_error_msg, response=self)
HTTPError: 401 Client Error: Unauthorized for url: https://cmr.earthdata.nasa.gov/search/collections.umm_json?has_granules=true&include_granule_counts=true&instrument=oci&page_size=0
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
Cell In[1], line 3
1 import earthaccess
2 auth = earthaccess.login()
----> 3 earthaccess.search_datasets(instrument="oci")
File /srv/conda/envs/notebook/lib/python3.10/site-packages/earthaccess/api.py:80, in search_datasets(count, **kwargs)
78 else:
79 query = DataCollections().parameters(**kwargs)
---> 80 datasets_found = query.hits()
81 logger.info(f"Datasets found: {datasets_found}")
82 if count > 0:
File [/srv/conda/envs/notebook/lib/python3.10/site-packages/earthaccess/search.py:88](https://oss.oel.smce.nasa.gov/srv/conda/envs/notebook/lib/python3.10/site-packages/earthaccess/search.py#line=87), in DataCollections.hits(self)
86 response.raise_for_status()
87 except requests.exceptions.HTTPError as ex:
---> 88 raise RuntimeError(ex.response.text) from ex
90 return int(response.headers["CMR-Hits"])
RuntimeError: {"errors":["Token [Bearer eyJXXXX_0FQ] has expired. Note the token value has been partially redacted."]}
Expected Behavior
My EDL token is expired, and I was expecting earthaccess to generate a new token for me (because #764 was purportedly fixed).
Steps To Reproduce
Wait until your EDL token expires ... then try the above.
Environment
- OS: Ubuntu 22.04.5 LTS
- Python: 3.10.14
- earthaccess installed from git commit 9784e4cee01a9d8d7514faea11cd3b80a12ae40f
Additional Context
No response
This does seem strange, particularly since I believe that about a month and a half ago, I had confirmed that this automatically created a new token for me, as my EDL token had also expired at that point.
Have you created a new token yet? If not, I have something I'd like you to do to help us debug this.
Alas, I had to carry on, and created a new token. I can try what you'd like me to do on ... 12/25/2024. Or maybe someone else will experience this sooner and can try, so do tell.
Alas, I had to carry on, and created a new token. I can try what you'd like me to do on ... 12/25/2024. Or maybe someone else will experience this sooner and can try, so do tell.
No worries. Mine expires on 11/11, so I'll set a reminder for myself to come back to this on 11/12, just to be sure it is expired.
I just experienced this same error and behavior. My one EDL token in EarthData Login was expired, I generated a new one and removed the old one, but I continued to receive the error for a few more hours at least. I didn't try the below code that was recommended to me from #484 to automatically generate the token from python because everything started working by the end of the day before I could try it, but will next time if needed:
auth = earthaccess.login()
auth.refresh_tokens()
I think I'm experiencing something similar...
The error
After running a notebook with earthaccess login/search/download many times and having it work fine, I'm getting what seems to be the same error as in the original post:
RuntimeError: {"errors":["Token [Bearer eyJXXXpDVLQ] has expired. Note the token value has been partially redacted."]}
What I've tried
So I've tried restarting the kernel and stopping+restarting the jupyter server (running this on my local machine), but that hasn't yet removed the error. And then I read the previous comment, and tried
auth.refresh_tokens()
but that shows
DeprecationWarning: No replacement, as tokens are now refreshed automatically.
I looked at urs.earthdata.nasa.gov, and I see that an existing token listed there expired today, so... Does this mean I need to regenerate a token at urs.earthdata.nasa.gov — or is there another way to generate a new token without going through the browser?
I think I'm experiencing something similar...
The error
After running a notebook with earthaccess login/search/download many times and having it work fine, I'm getting what seems to be the same error as in the original post:
RuntimeError: {"errors":["Token [Bearer eyJXXXpDVLQ] has expired. Note the token value has been partially redacted."]}What I've tried
So I've tried restarting the kernel and stopping+restarting the jupyter server (running this on my local machine), but that hasn't yet removed the error. And then I read the previous comment, and tried
auth.refresh_tokens() but that shows
DeprecationWarning: No replacement, as tokens are now refreshed automatically.I looked at urs.earthdata.nasa.gov, and I see that an existing token listed there expired today, so... Does this mean I need to regenerate a token at urs.earthdata.nasa.gov — or is there another way to generate a new token without going through the browser?
Which version of earthaccess are you using?
Can you provide a traceback?
This should not be happening because earthaccess now uses the find_or_create_token function, which will automatically find your existing token (if you have one), or create a new one (if you don't have one, or if the one you have is expired).
To confirm, I deleted my token (via the browser at https://urs.earthdata.nasa.gov/users/MY_USERNAME/user_tokens, replacing MY_USERNAME with my actual username), and then I ran the following on my computer:
import earthaccess
earthaccess.login()
This automatically created a new token for me (since I just deleted the only token I had), which I confirmed by refreshing my tokens page where I had just deleted my only token, and I saw a new token.
Aside from a traceback, can you also provide a minimum code example? I'm wondering if perhaps there's a particular code path that is failing to make the right call to automatically grab a non-expired token.
I'm also wondering if there's a bug in URS when making a call to get a token on the same day that the UI shows as the token's expiry date.
@chuckwondo, responding to points in your comment...
Which version of earthaccess are you using?
0.14.0
Can you provide a traceback?
I unfortunately/fortunately already generated a new token via the browser (at https://urs.earthdata.nasa.gov/users/MY_USERNAME/user_tokens, replacing MY_USERNAME with my actual username) in order to get past this and run the code I was trying to run. That seemed to resolve the error. I'm pretty sure the traceback was identical to that in the first post on this issue, including both the HTTP 401 error and the RuntimeError.
Aside from a traceback, can you also provide a minimum code example?
Seems unlikely it will help without the error/traceback being generated anymore, but the code that was generating the error is:
import earthaccess
earthaccess.login()
results = earthaccess.search_data(
short_name="DSCOVR_EPIC_L2_TO3",
version="03",
temporal=("2025-02-01T00:00:00", "2025-02-01T04:59:59"),
)
I'm also wondering if there's a bug in URS when making a call to get a token on the same day that the UI shows as the token's expiry date.
That's possible! The token's expiration date was exactly today, 6 May 2025.
I deleted my token again, and ran your example code, and things worked as expected (a new token was automatically created behind the scenes, and no error occurred).
At this point, I suspect this could be a bug on the Earthdata end, perhaps only on the date that the token is indicated to expire.
However, before I open an Earthdata Support ticket, I have set a reminder for myself to try this again on the date that my current token is set to expire to see if I can reproduce the error. If so, then I'll open a support ticket at that point in time. If not, then I have no clue what's going on and we'll just have to wait for it to happen again and attempt to gather additional details that we're not seeing at this point.
that sounds good, thanks @chuckwondo for looking into this further!
I am also getting this error, and I see that my expiration date is today:
>>> import earthaccess
>>> earthaccess.get_edl_token()['expiration_date']
'06/15/2025'
My session is similar to those above:
Python 3.13.5 | packaged by conda-forge | (main, Jun 13 2025, 01:08:30) [Clang 18.1.8 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import earthaccess
>>> earthaccess.__version__
'0.14.0'
>>> auth = earthaccess.login()
>>> auth.authenticated
True
>>> earthaccess.search_data(short_name='OPERA_L3_DISP-S1_V1')
Traceback (most recent call last):
File "/Users/staniewi/repos/test-vz-opera/.pixi/envs/default/lib/python3.13/site-packages/earthaccess/search.py", line 463, in hits
response.raise_for_status()
~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/Users/staniewi/repos/test-vz-opera/.pixi/envs/default/lib/python3.13/site-packages/requests/models.py", line 1026, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://cmr.earthdata.nasa.gov/search/granules.umm_json?short_name=OPERA_L3_DISP-S1_V1&page_size=0
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<python-input-4>", line 1, in <module>
earthaccess.search_data(short_name='OPERA_L3_DISP-S1_V1')
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/staniewi/repos/test-vz-opera/.pixi/envs/default/lib/python3.13/site-packages/earthaccess/api.py", line 138, in search_data
granules_found = query.hits()
File "/Users/staniewi/repos/test-vz-opera/.pixi/envs/default/lib/python3.13/site-packages/earthaccess/search.py", line 466, in hits
raise RuntimeError(ex.response.text) from ex
RuntimeError: {"errors":["Token [Bearer eyJXXX75KvQ] has expired. Note the token value has been partially redacted."]}
refresh_tokens failed for me
>>> auth.refresh_tokens()
<python-input-5>:1: DeprecationWarning: No replacement, as tokens are now refreshed automatically.
True
>>> earthaccess.search_data(short_name='OPERA_L3_DISP-S1_V1')
Traceback (most recent call last):
Thanks @scottstanie for reporting this. Given my suspicion that this happens only on the exact date of expiration, if you have not already manually generated a new token, would you mind running your code again to see if it works?
If you haven't manually created a new token and rerunning your code works now (different date than the expiration date), I will open an Earthdata Support ticket, as I believe this should be reasonable evidence of a bug on their end, where attempting to use a token on the same date as its expiration date fails to cause their system to automatically generate a new token.
I did regenerate one, but I deleted it by going to https://urs.earthdata.nasa.gov/users/myusername/user_tokens . When I ran the eathaccess.search_data, it generated a new token for me.
Thanks for the info. I think this still points to there being a bug on the Earthdata API side of things, so I've opened an Earthaccess Support ticket (#107729). I'll update this thread once I hear back from support.
I just received a reply from Earthdata Support:
Thanks for reaching out about this issue. We have filed this as a bug and should have this corrected in a release in the upcoming weeks.
I have not received an update from Earthdata Support, but they have acknowledged receipt of the bug report.
To add to the mix, I had 2 EDL tokens, and one of them showed an expiry of yesterday (July 7), so here's what I tried:
First, I tried to directly use the token showing an expiry of July 7 via curl to download a granule file, and I was denied, with a message indicating that I was using an expired token:
$ curl -H "Authorization: Bearer eyJ0...SOWA" https://data.ornldaac.earthdata.nasa.gov/protected/gedi/GEDI_L4A_AGB_Density_V2_1/data/GEDI04_A_2019107224731_O01958_01_T02638_02_002_02_V002.h5
{"error":"invalid_token","error_description":"This access token has expired"}
I then used the fetch_or_create_token endpoint to see what would happen, and I received my other token, which expires on July 28:
$ curl --request POST --url https://urs.earthdata.nasa.gov/api/users/find_or_create_token --header 'Authorization: Basic ...'
{"access_token":"eyJ0...Cn7A","token_type":"Bearer","expiration_date":"07/28/2025"}
So it seems that things work as expected when one token is expired and a second token has not expired.
I'll revisit this on July 28 to attempt the same steps, but without a secondary token in place, to see what happens.
I just received an update from Earthaccess Support (Jul 8):
We have a fix for this issue in testing, and the change should be deployed in the next 2 weeks.
Today (July 28, 2025), I have exactly 1 token, and it shows today as its expiry date.
Therefore, I ran the following command with the token to see if the problem originally reported persists (where I used my token in place of REDACTED):
curl -O -L --no-netrc -H "Authorization: Bearer REDACTED" https://data.lpdaac.earthdatacloud.nasa.gov/lp-prod-protected/GEDI02_A.002/GEDI02_A_2024333234311_O33780_03_T10654_02_004_02_V002/GEDI02_A_2024333234311_O33780_03_T10654_02_004_02_V002.h5
This succeeded!
Further, I tried the following command as well (replacing USERNAME with my username, and getting prompted for my password):
curl --request POST --url https://urs.earthdata.nasa.gov/api/users/find_or_create_token -u USERNAME
and it returned my current token (the one showing that it expires today).
This shows consistency between the 2 responses because I am allowed to use the token marked as expiring today and "fetch or create token" fetches the very same token, avoiding creation of a new token.
Therefore, I am closing this issue as resolved.