Skip to content

Unable to create polaris catalog due to missing headers #2655

@rinzool

Description

@rinzool

Apache Iceberg version

0.10.0 (latest release)

Please describe the bug 🐞

Description

Since version 0.10.0 it is not possible to create a Polaris catalog with credential parameter.

For example:

catalog_parameters = {
    "type": "rest",
    # ...
    "scope": "PRINCIPAL_ROLE:ALL",
    "header.Polaris-Realm": "my-realm",
    "credential": f"{client_id}:{client_secret}"
}

catalog = load_catalog("default", **catalog_parameters)

This code fails with error RESTError: MissingOrInvalidRealm: Missing or invalid realm.

The exact same code works with pyiceberg 0.9.1.

Cause

Polaris needs header Polaris-Realm.

We can see in the full stacktrace (see below) that the error occurs when we create the AuthManager line 266: https://github.com/apache/iceberg-python/blob/pyiceberg-0.10.0/pyiceberg/catalog/rest/__init__.py#L266.

But headers are injected after initializing AuthManager at line 269:
https://github.com/apache/iceberg-python/blob/pyiceberg-0.10.0/pyiceberg/catalog/rest/__init__.py#L269.

Full stacktrace
File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/__init__.py:128](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/__init__.py#line=127), in load_rest(name, conf)
    125 def load_rest(name: str, conf: Properties) -> Catalog:
    126     from pyiceberg.catalog.rest import RestCatalog
--> 128     return RestCatalog(name, **conf)

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py:234](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py#line=233), in RestCatalog.__init__(self, name, **properties)
    232 super().__init__(name, **properties)
    233 self.uri = properties[URI]
--> 234 self._fetch_config()
    235 self._session = self._create_session()

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py:364](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py#line=363), in RestCatalog._fetch_config(self)
    361 if warehouse_location := self.properties.get(WAREHOUSE_LOCATION):
    362     params[WAREHOUSE_LOCATION] = warehouse_location
--> 364 with self._create_session() as session:
    365     response = session.get(self.url(Endpoints.get_config, prefixed=False), params=params)
    366 try:

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py:266](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py#line=265), in RestCatalog._create_session(self)
    264     session.auth = AuthManagerAdapter(AuthManagerFactory.create(auth_impl or auth_type, auth_type_config))
    265 else:
--> 266     session.auth = AuthManagerAdapter(self._create_legacy_oauth2_auth_manager(session))
    268 # Set HTTP headers
    269 self._config_headers(session)

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py:295](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/__init__.py#line=294), in RestCatalog._create_legacy_oauth2_auth_manager(self, session)
    285 auth_url = self.auth_url if client_credentials is not None else None
    287 auth_config = {
    288     "session": session,
    289     "auth_url": auth_url,
   (...)
    292     "optional_oauth_params": self._extract_optional_oauth_params(),
    293 }
--> 295 return AuthManagerFactory.create("legacyoauth2", auth_config)

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py:321](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py#line=320), in AuthManagerFactory.create(cls, class_or_name, config)
    318     except Exception as err:
    319         raise ValueError(f"Could not load AuthManager class for '{class_or_name}'") from err
--> 321 return manager_cls(**config)

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py:94](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py#line=93), in LegacyOAuth2AuthManager.__init__(self, session, auth_url, credential, initial_token, optional_oauth_params)
     92 self._credential = credential
     93 self._optional_oauth_params = optional_oauth_params
---> 94 self._refresh_token()

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py:122](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py#line=121), in LegacyOAuth2AuthManager._refresh_token(self)
    120 def _refresh_token(self) -> None:
    121     if self._credential is not None:
--> 122         self._token = self._fetch_access_token(self._credential)

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py:116](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/auth.py#line=115), in LegacyOAuth2AuthManager._fetch_access_token(self, credential)
    114     response.raise_for_status()
    115 except HTTPError as exc:
--> 116     _handle_non_200_response(exc, {400: OAuthError, 401: OAuthError})
    118 return TokenResponse.model_validate_json(response.text).access_token

File [/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/response.py:111](https://poc-dwh-qfn.forepaas.io/opt/conda/lib/python3.11/site-packages/pyiceberg/catalog/rest/response.py#line=110), in _handle_non_200_response(exc, error_handler)
    108     errs = ", ".join(err["msg"] for err in e.errors())
    109     response = f"RESTError {exc.response.status_code}: Received unexpected JSON Payload: {exc.response.text}, errors: {errs}"
--> 111 raise exception(response) from exc

RESTError: MissingOrInvalidRealm: Missing or invalid realm

Solution

Move self._config_headers(session) instruction in the beginning of _create_session method.

Willingness to contribute

  • I can contribute a fix for this bug independently
  • I would be willing to contribute a fix for this bug with guidance from the Iceberg community
  • I cannot contribute a fix for this bug at this time

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions