0

I have an Exception class written in Python for handling my custom AWS Lambda exceptions as below:

class HTTPException(Exception):
def __new__(cls, error_code, error_message):
    return {
        "statusCode": error_code,
        "body": error_message,
        "headers": {"Access-Control-Allow-Origin": "*"},
    }

@classmethod
def magic_func(cls, err):
    return cls(
        error_code=err.Code,
        error_message=err.Message,
    )

When I try to invoke this through AWS lambda it throws: TypeError: exceptions must derive from BaseException. What am I doing wrong here ?

1 Answer 1

1
class HTTPException(Exception):
    def __new__(cls, error_code, error_message):
        return {
            "statusCode": error_code,
            "body": error_message,
            "headers": {"Access-Control-Allow-Origin": "*"},
        }

is violating the contract for __new__, failing to return a new instance of HTTPException, and instead returning a random dict object. If you intended to wrap said dict in the exception, the sane way to do it would be to use __init__ (because you don't want to return something that isn't and HTTPException, nor use singletons or caches or immutable objects, which are the reasons to use __new__ instead), and delegate the dict up to the superclass initializer:

class HTTPException(Exception):
    def __init__(self, error_code, error_message):  # __init__ taking self
        # Pass dict up to superclass initializer
        super().__init__({
            "statusCode": error_code,
            "body": error_message,
            "headers": {"Access-Control-Allow-Origin": "*"},
        })

    @classmethod
    def magic_func(cls, err):
        return cls(
            error_code=err.Code,
            error_message=err.Message,
        )

Hopefully, whatever catches your exception knows to look for that attached dict, because if not, you're going to need to find where that's happening and return the dict the expected way.

Sign up to request clarification or add additional context in comments.

7 Comments

But I read somewhere that it isn't a good thing to return from init. Excuse my naiveness.
@BrattyNeal: You don't return from __init__. Look at the modified code. __init__ initializes an existing object provided to it (self), you don't need to return a thing. __new__ needs to return, but it should still be an instance of the cls passed to it, which your original code was ignoring, returning a dict instead.
When I try to return an Exception using your above solution, I get "Unable to marshal response: Object of type HTTPException is not JSON serializable", "errorType": "Runtime.MarshalError" in my AWS API gateway for my lambda. Looks like it returns an object(class object) instead of my dict structure.
@BrattyNeal: Yes... You can't raise a dict as an exception. You can extract the dict from the exception wherever you catch it, should you need to return it (the .args attribute of the exception is a tuple containing the arguments, so exceptionobject.args[0] will be your dict). I have a feeling you've got an XY problem here, or a fundamental misunderstanding of how exceptions work. You can only raise instances of BaseException or its subclasses. AWS wants you to return a dict. Trying to mix the two too closely will fail.
Are you stating that maintaining a custom Exception class was a bad idea ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.