How to catch `botocore.errorfactory.UserNotFoundException`?
Asked Answered
U

3

34

I am using AWS Cognito to make OAuth server. I am now creating the exception handler in case use does not exist, but requests intended to get one

ipdb> pk
'David'
ipdb> res = self.cognito_client.admin_get_user(
            UserPoolId=settings.AWS_USER_POOL_ID,
            Username=pk
        )
*** botocore.errorfactory.UserNotFoundException: An error occurred (UserNotFoundException) when calling the AdminGetUser operation: User does not exist.
Traceback (most recent call last):
  File "/Users/sarit/.pyenv/versions/futuready-titan/lib/python3.8/site-packages/botocore/client.py", line 316, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/Users/sarit/.pyenv/versions/futuready-titan/lib/python3.8/site-packages/botocore/client.py", line 626, in _make_api_call
    raise error_class(parsed_response, operation_name)
boto3==1.12.15            # via -r el.in
botocore==1.15.15         # via boto3, s3transfer
django==3.0.3
python3.8.1

I had checked with botocore source code UserNotFoundException

Question:
How can I specifically catch this exception?

Unattended answered 16/3, 2020 at 9:12 Comment(3)
Have you just created a user, or it is old? Usually, it takes about one day to activate the amazon account.Snavely
What did you try already? (pun intended :p)Disyllable
@Disyllable I had tried BotoCoreError, but it is not workUnattended
I
40

When an exception is created by botocore.error_factory then it is not possible to directly import it. Instead of direct import, you should use generated classes for exceptions.

A list of possible exceptions is provided for each operation in the documentation. For example, for CognitoIdentityProvider.Client.admin_get_user, possible exceptions are:

CognitoIdentityProvider.Client.exceptions.ResourceNotFoundException
CognitoIdentityProvider.Client.exceptions.InvalidParameterException
CognitoIdentityProvider.Client.exceptions.TooManyRequestsException
CognitoIdentityProvider.Client.exceptions.NotAuthorizedException
CognitoIdentityProvider.Client.exceptions.UserNotFoundException
CognitoIdentityProvider.Client.exceptions.InternalErrorException

There is an example of how to get the list of examples for a client and how to handle it (of course list of exceptions is depend from operation):

import boto3

eks = boto3.client('eks')
print(dir(eks.exceptions))
# ['BadRequestException', 
# 'ClientError', 
# 'ClientException',
# 'InvalidParameterException',
# 'InvalidRequestException',
# 'NotFoundException',
# 'ResourceInUseException',
# 'ResourceLimitExceededException',
# 'ResourceNotFoundException',
# 'ServerException',
# 'ServiceUnavailableException',
# 'UnsupportedAvailabilityZoneException', ...]
try:
    response = eks.list_nodegroups(clusterName='my-cluster')
except eks.exceptions.ResourceNotFoundException as e:
    # do something with e
    print("handled: " + str(e))

cognito_idp = boto3.client('cognito-idp')
print(dir(cognito_idp.exceptions))
# [ 'ClientError', 
# 'ConcurrentModificationException',
# 'DeveloperUserAlreadyRegisteredException',
# 'ExternalServiceException',
# 'InternalErrorException',
# 'InvalidIdentityPoolConfigurationException',
# 'InvalidParameterException',
# 'LimitExceededException',
# 'NotAuthorizedException',
# 'ResourceConflictException',
# 'ResourceNotFoundException',
# 'TooManyRequestsException', ... ]
try:
    response = cognito_idp.admin_get_user(
        UserPoolId='pool_id',
        Username='username'
    )
except cognito_idp.exceptions.UserNotFoundException as e:
    # do something with e
    print("handled: " + str(e))

Additionally, you may catch the less typed botocore.exceptions.ClientError instead of specific ones:

import boto3
import botocore.exceptions

try:
    response = cognito_idp.admin_get_user(
        UserPoolId='pool_id',
        Username='username'
    )
except botocore.exceptions.ClientError as e:
    # do something with e
    print("handled: " + str(e))
Institute answered 25/7, 2021 at 19:11 Comment(2)
This is such a pain. I can't understand why doesn't AWS just expose the exceptions. What if I have a test case where I want a side effect to raise the exception but where I am mocking a client such as Glue?Vierno
boto is such a shitty library, just the an excellent example of how you should not program in pythonNolpros
E
4

There's two ways, you can catch the exception directly if it is exposed on the client, or import from botocore.exceptions and use that instead.

Option 1:

try: 
    res = self.cognito_client.admin_get_user(
              UserPoolId=settings.AWS_USER_POOL_ID,
              Username=pk
          )
except self.cognito_client.exceptions.UserNotFoundException as e:
    print(e)

Option 2:

from botocore.exceptions import UserNotFoundException

try: 
    res = self.cognito_client.admin_get_user(
              UserPoolId=settings.AWS_USER_POOL_ID,
              Username=pk
          )
except UserNotFoundException as e:
    print(e)

See botos error handling documentation for more detailed information.

Entertain answered 22/6, 2020 at 21:29 Comment(2)
cannot import name 'UserNotFoundException' from 'botocore.exceptions' (/home/ec2-user/anaconda3/envs/python38/lib/python3.8/site-packages/botocore/exceptions.py)Botelho
This does not work. As @NicWanavit stated, the import line throws an error.Ratiocinate
P
4

This is certainly not ideal, but I am able to catch it with:

from botocore.exceptions import ClientError

try:
    func_that_interacts_with_cognito()
except ClientError:
    # This happens when the user is not found.
    print("It happened again ...")
Parliament answered 12/8, 2020 at 19:58 Comment(1)
This actually works for me as I need to catch a NotAuthorizedException which is created by botocore.error_factoryBrillatsavarin

© 2022 - 2024 — McMap. All rights reserved.