How to catch `botocore.errorfactory.UserNotFoundException`?

Viewed 7983

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?

3 Answers

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))

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.

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 ...")
Related