Exception `default-profile` not found in config file while creating SH Session with token

Hi there,

I’m using sentinelhub==3.10.0 python SDK.

I’m occasionally seeing this exception <class ‘KeyError’>, with exception message: ‘Profile default-profile not found in configuration file.’ while trying to initialise a SentinelHubSession with token using the method SentinelHubSession.from_token(token).

This exception is not happening always, its only happening occasionally. Below is the stacktrace:

  File "/sentinel2_service/sentinel2/models/sentinel_hub_client.py", line 17, in __init__
    self.sh_session = SentinelHubSession.from_token(token)
  File "/venv/lib/python3.8/site-packages/sentinelhub/download/session.py", line 85, in from_token
    return cls(_token=token, refresh_before_expiry=None)
  File "/venv/lib/python3.8/site-packages/sentinelhub/download/session.py", line 62, in __init__
    self.config = config or SHConfig()
  File "/venv/lib/python3.8/site-packages/sentinelhub/config.py", line 127, in __init__
    loaded_kwargs = SHConfig.load(profile=profile).to_dict(mask_credentials=False)
  File "/venv/lib/python3.8/site-packages/sentinelhub/config.py", line 162, in load
    raise KeyError(f"Profile `{profile}` not found in configuration file.")

Seems to be an issue with file write and followed by read inconsistency. But not sure.

Any help what might be the actual issue? and what can be done to rectify this issue?

@chung.horng Can you help here :slight_smile: ?

Hi,

Please can you share the code you are using to generate the token so we can start to replicate the issue you having please.

Hi @william.ray

Thanks for the reply.

I have also started seeing the same " default-profile not found in configuration file" error while doing just this: sh_config = SHConfig(). This is run in many threads. I hope running this line of code (i.e, initialising SHConfig()) is thread-safe.

Also the code I pointed out in my first post sh_session = SentinelHubSession.from_token(token) is also run in many threads simultaneously. I hope this is also a thread-safe operation or Am I wrong here?

Coming to your question: We generate token on a different machine and share the token across many machines (VMs or Kubernetes pods).

We generate token like this:

            config = SHConfig()
            config.sh_client_id = client_id
            config.sh_client_secret = client_secret
            session = SentinelHubSession(config=config)
            token = session.token

We only generate token just few times every hour and share it across many machines(kubernetes pods).

Hi @MSFTFB

Some quick background. When SHConfig() is called, it will try to load settings from the config.toml file (located in ~/.config/sentinelhub/ or similar, check SHConfig.get_config_location() for specifics).

If such a file does not exist, it tries to create it. If it creates such a file, it should have the default profile already inside. Judging by this error some likely causes are:

  1. there already exists such a file, but it does not have the default-profile set up.
  2. the file creation somehow goes sideways and nothing is written to the file (but the file is created).

Point 2 is even more likely if multiple threads are trying to do this step all at once, which sounds likely in your case.

Options I would suggest:

  1. Make sure such a file is initialized in the environment before you start with your workers.
  2. Since you set credentials by hand, you can also use SHConfig(use_defaults=True). This way there wont be an attempt to read from the configuration file.

As for .from_token, it should be thread safe (it just parses initialization parameters from the given token). However by using this it will disable automatic token refreshing. If your threads are short lived then this shouldnt be a problem, but for longer lived threads check this tutorial to see if some of the suggested approaches could be used.

Hi @ziga.luksic

Thanks for the reply.

Want to add few things to my post:

  1. We are managing token refresh when its near expiry. So that is not an issue.
  2. We don’t set or create any file during initialisation and we don’t want to either (unless that is the fix to this problem)
  3. We don’t set credentials. We only set them in one of our machines. In all other machines (pods), we only use the token that is created by one of our machines(we write the token to redis and share it among pods).

Since we don’t set any credentials and only create the SentinelHubSession using the SentinelHubSession.from_token method, can you suggest what can we do here, to preven the issue?

Do you suggest creating a config.toml file with same contents as default-profile would have, instead of SDK trying to create it?

I can quickly see the contents of that file in runtime and add code to create it during initialisation of my server. But can there be a better way to solve this?

Ah, I see that the core of the issue is that SentinelhubSession.from_token(my_token) doesn’t let you pass a SHConfig object to the session directly (because it is technically never used), but behind the scenes it is nonetheless created and that causes issues. Something like this, correct?

One way is to have the config file present on the machine which (i believe) only has to contain a line [default-profile] and nothing else.

Another way would be to avoid the file lookup, but this currently has to rely on a hidden parameter of the API.
You can do:

config = SHConfig(use_defaults=True)
session = SentinelHubSession(config=config, refresh_before_expiry=None, _token=token)

This will create the same kind of session as from_token would, except it will use a default config, and wont look at any file. The drawback here is, that we’re using a hidden parameter and it is harder to guarantee that this wont break in a future version.

For your information:

This exception is also being raised when we do just SHConfig(). In another place of our code, we initialise the SHConfig object with empty parameters. The same exception is happening there as well.

You might need to look at it too.

P.S: We don’t create any profile config file. We leave it to the SDK to create/use default profile or whatever it uses under the hood.

Core issue is, why is initializing SHConfig() with empty parameters resulting in an exception??

Because it tries to create a config file, but fails to do so. If you want to avoid creating a file, use SHConfig(use_defaults=True)

1 Like

Sure, will try it.

Also, just initialising SHConfig() at the server startup also should create the file at the default location and any subsequent SHConfig() initialisation calls should just read that file from there and not result in exceptions right? Can this be another way of solving this?

Just curious why config file create is failing occasionally (its not failing always, its transient). Maybe because of multiple threads trying to do it at the same time? If yes, you can fix it by adding a lock around the default config file creation logic? Basically adding lock before creating config file here in the code: sentinelhub-py/sentinelhub/config.py at f9f29c909e15bae2be2768a29c312ed24acda83e · sentinel-hub/sentinelhub-py · GitHub

I suspect that the issue is because of multiple threads trying to access an file that is being created. The entire package assumes that the package is available at all times and so far we suggested different approaches of sharing access tokens (via shared memory etc.) that do not have this issue.

If we see more users with similar problems, then yes, we might add a multiprocessing lock around the file IO. Thank you for the suggestion.