401 Unauthorized Error when initializing Butler for DP1 in RSP notebook

Hi Rubin Community,

I’m sorry for posting this during the weekend—I know it’s not ideal, but I’ve been stuck on this issue and wanted to get it out there in case anyone has insights.

I’m trying to initialize a Butler instance for the DP1 repository in a RSP notebook (using lsst-scipipe-10.1.0 environment), but I’m getting a 401 Unauthorized error on the /api/butler/repo/dp1/v1/universe endpoint. This started today, even though I’m accessing and logging in the same way as always.

Here’s the full traceback for reference:

from lsst.daf.butler import Butler
butler = Butler("dp1", collections="LSSTComCam/DP1")

---------------------------------------------------------------------------
HTTPStatusError                           Traceback (most recent call last)
File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_http_connection.py:220, in RemoteButlerHttpConnection._send_request(self, request)
    219 response = self._send_with_retries(request, stream=False)
--> 220 self._handle_http_status(response, request.request_id)
    221 return response

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_http_connection.py:274, in RemoteButlerHttpConnection._handle_http_status(self, response, request_id)
    269     # If model is None, server sent an expected error code, but
    270     # the body wasn't in the expected JSON format.  This likely
    271     # means some HTTP thing between us and the server is
    272     # misbehaving.
--> 274 response.raise_for_status()

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/lib/python3.12/site-packages/httpx/_models.py:763, in Response.raise_for_status(self)
    762 message = message.format(self, error_type=error_type)
--> 763 raise HTTPStatusError(message, request=request, response=self)

HTTPStatusError: Client error '401 Unauthorized' for url 'https://data.lsst.cloud/api/butler/repo/dp1/v1/universe'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401

The above exception was the direct cause of the following exception:

ButlerServerError                         Traceback (most recent call last)
Cell In[3], line 1
----> 1 butler = Butler("dp1", collections="LSSTComCam/DP1")
      2 assert butler is not None

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/_butler.py:166, in Butler.__new__(cls, config, collections, run, searchPaths, writeable, inferDefaults, without_datastore, metrics, **kwargs)
    152 def __new__(
    153     cls,
    154     config: Config | ResourcePathExpression | None = None,
   (...)
    163     **kwargs: Any,
    164 ) -> Butler:
    165     if cls is Butler:
--> 166         return Butler.from_config(
    167             config=config,
    168             collections=collections,
    169             run=run,
    170             searchPaths=searchPaths,
    171             writeable=writeable,
    172             inferDefaults=inferDefaults,
    173             without_datastore=without_datastore,
    174             metrics=metrics,
    175             **kwargs,
    176         )
    178     # Note: we do not pass any parameters to __new__, Python will pass them
    179     # to __init__ after __new__ returns sub-class instance.
    180     return super().__new__(cls)

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/_butler.py:355, in Butler.from_config(cls, config, collections, run, searchPaths, writeable, inferDefaults, without_datastore, metrics, **kwargs)
    352     # Assume this is being created by a client who would like
    353     # default caching of remote datasets.
    354     factory = RemoteButlerFactory.create_factory_from_config(butler_config)
--> 355     return factory.create_butler_with_credentials_from_environment(
    356         butler_options=options, use_disabled_datastore_cache=False
    357     )
    358 case _:
    359     raise TypeError(f"Unknown Butler type '{butler_type}'")

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_factory.py:132, in RemoteButlerFactory.create_butler_with_credentials_from_environment(self, butler_options, use_disabled_datastore_cache)
    127 if token is None:
    128     raise RuntimeError(
    129         "Attempting to connect to Butler server,"
    130         " but no access credentials were found in the environment."
    131     )
--> 132 return self.create_butler_for_access_token(
    133     token, butler_options=butler_options, use_disabled_datastore_cache=use_disabled_datastore_cache
    134 )

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_factory.py:111, in RemoteButlerFactory.create_butler_for_access_token(self, access_token, butler_options, use_disabled_datastore_cache)
    109 if butler_options is None:
    110     butler_options = ButlerInstanceOptions()
--> 111 return RemoteButler(
    112     connection=RemoteButlerHttpConnection(
    113         http_client=self.http_client, server_url=self.server_url, access_token=access_token
    114     ),
    115     defaults=RegistryDefaults.from_butler_instance_options(butler_options),
    116     cache=self._cache,
    117     use_disabled_datastore_cache=use_disabled_datastore_cache,
    118 )

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_remote_butler.py:163, in RemoteButler.__new__(cls, connection, defaults, cache, use_disabled_datastore_cache, metrics)
    161 self._registry_defaults = DefaultsHolder(defaults)
    162 self._registry = RemoteButlerRegistry(self, self._registry_defaults, self._connection)
--> 163 defaults.finish(self._registry)
    165 return self

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/registry/_defaults.py:219, in RegistryDefaults.finish(self, registry)
    216 if hasattr(self, "_finished"):
    217     return
--> 219 allGovernorDimensions = registry.dimensions.governor_dimensions
    220 if not self._kwargs.keys() <= allGovernorDimensions.names:
    221     raise TypeError(
    222         "Only governor dimensions may be identified by a default data "
    223         f"ID, not {self._kwargs.keys() - allGovernorDimensions.names}.  "
    224         "(These may just be unrecognized keyword arguments passed at "
    225         "Butler construction.)"
    226     )

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_registry.py:111, in RemoteButlerRegistry.dimensions(self)
    109 @property
    110 def dimensions(self) -> DimensionUniverse:
--> 111     return self._butler.dimensions

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_remote_butler.py:193, in RemoteButler.dimensions(self)
    190     if cache.dimensions is not None:
    191         return cache.dimensions
--> 193 response = self._connection.get("universe")
    194 model = parse_model(response, GetUniverseResponseModel)
    196 config = DimensionConfig.from_simple(model.universe)

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_http_connection.py:167, in RemoteButlerHttpConnection.get(self, path, params)
    145 """Send a GET request to the Butler server.
    146 
    147 Parameters
   (...)
    164     If there is an issue communicating with the server.
    165 """
    166 request = self._build_request("GET", path, params=params)
--> 167 return self._send_request(request)

File /opt/lsst/software/stack/conda/envs/lsst-scipipe-10.1.0/share/eups/Linux64/daf_butler/g6dd59efbe6+ec144cf465/python/lsst/daf/butler/remote_butler/_http_connection.py:223, in RemoteButlerHttpConnection._send_request(self, request)
    221     return response
    222 except httpx.HTTPStatusError as e:
--> 223     raise ButlerServerError(
    224         client_request_id=request.request_id, status_code=e.response.status_code
    225     ) from e
    226 except httpx.HTTPError as e:
    227     raise ButlerServerError(client_request_id=request.request_id) from e

ButlerServerError: Error while communicating with Butler server.  Request ID: 47b83aba-abee-4632-acf2-52c2dceed62b

Has anyone seen this before or know what might be going on?

Thanks in advance, and apologies again for the weekend timing!

Best,
Karen

Hi Karen,

Thank you for your question!

That is definitely a confusing error. I am afraid I haven’t been able to reproduce it myself; so I do not have an immediate answer for you. Are you running this notebook on https://data.lsst.cloud ? Have you tried running the notebook again since you ran into this error? (E.g., sometimes, like 3PM-5PM US PDT on “Patch Thursdays,” updates may be going on that affect some services on the RSP.) And, if you have tried running the notebook again and received the same error, have you tried logging out of the RSP and logging back in?

Let us know, and we will try to find a solution for this as soon as we can!

Thanks!

Best regards,
Douglas

Hello Douglas, thanks your answer!

Yes, I tried again just now and this keep happening. I already log out and back. What else could raise this authentication error?

Could it be a problem related with GitHub authentication?