Is there a way to customise a Boto3 Lambda exception message in the form of a HTTP response and return it while also sending a forced failed?
Here is an example
except Exception as e:
print ('\nException : failed to invoke jobs.')
print ('Error : ' + str(e) + '\n')
return {
'statusCode': 500,
'body': 'Exception : failed to invoke EMR jobs'
}
So the customised message is now returned but the Lambda still returns a job success rather than failure.
In order to send the job failure the exception block can be changed to -
except Exception as e:
print ('\nException : failed to invoke jobs.')
print ('Error : ' + str(e) + '\n')
raise
But now the custom error message has been lost.
Is there a way to combine the custom response error message and to fail the Lambda job?
To get the custom error message as output for the lambda, you need to actually raise the exception with the custom error message.
except Exception as e:
custom_error = '\nException : failed to invoke jobs.\n'
custom_error += 'Error : ' + str(e) + '\n'
raise Exception(custom_error)
And you will get an error message like:
{
"errorMessage": "Exception : failed to invoke jobs. ....",
"stackTrace": [
[
"/var/task/lambda_function.py",
3,
"my_always_fails_handler",
"raise Exception(custom_error)"
]
],
"errorType": "Exception"
}
You can find more on the AWS documentation that you can find here Python exceptions in lambdas
You didn't mention it, but you're probably using AWS API Gateway to in front of your lambda.
You can use API Gateway "integration response" to transform your failed result to the HTTP response.
Here's a link to the docs
Related
I have a small python code in which I am using exception handling.
def handler(event):
try:
client = boto3.client('dynamodb')
response = client.scan(TableName=os.environ["datapipeline_table"])
return response
except Exception as error:
logging.exception("GetPipelinesError: %s",json.dumps(error))
raise GetPipelinesError(json.dumps({"httpStatus": 400, "message": "Unable to fetch Pipelines"}))
class GetPipelinesError(Exception):
pass
pylint warning gives me " Consider explicitly re-raising using the 'from' keyword ".
I saw few other posts, where they used from and raised an error. I made modifications like this
except Exception as GetPipelinesError:
logging.exception("GetPipelinesError: %s",json.dumps(GetPipelinesError))
raise json.dumps({"httpStatus": 400, "message": "Unable to fetch Pipelines"}) from GetPipelinesError
Is this the right way to do ?
No. The purpose of raise-from is to chain exceptions. The correct syntax in your case is:
except Exception as error:
raise GetPipelinesError(json.dumps(
{"httpStatus": 400, "message": "Unable to fetch Pipelines"})) from error
The expressions that follow raise and from must be exception classes or instances.
I am new to python. Is there anyway I can raise error in Lambda function? I have a pyqt5 button that connect to a lambda function. I would like to catch the error in lambda function and show it to user. Is there anyway I can bring the message(string) out of the lambda function and then show it to user or is there anyway I can raise an error inside lambda function? I have a try/except in the place where lambda was apply. What I hope is when the lambda function have error and the error can be catch outside of the lambda function.
example:
def test1:
*****
def test2(a):
****
try:
x=lambda(test2(test1))
except Exception as e:
print(e) <<< want it to go here.
In your code you only assign a lambda function to a variable without any calling. In addition, the syntax for lambda seems to be wrong. You could change your code something like as follows:
def test1:
*****
def test2(a):
****
a_func = lambda x: test2(test1(x))
try:
a_func(some_input)
except Exception as e:
print(e)
import os
import boto3
import json
from botocore.exceptions import ClientError
def lambda_handler(event, context):
# Fetch Datebase Identifier Environment variable
DBinstance = os.environ['DBInstanceName']
#create an Rds client
context.rds_client = boto3.client('rds')
# Describe instance
response = context.rds_client.describe_db_instances(DBInstanceIdentifier=DBinstance )
#Check the status of rds instance
status = response['DBInstances'][0]['DBInstanceStatus']
# If Rds Instance is in stopped stop, It will be started
if status == "stopped":
try:
#Stopping the Rds instance
response = context.rds_client.start_db_instance( DBInstanceIdentifier=DBinstance )
#send logs to cloudwatch
print ('Success :: Starting Rds instance:', DBinstance)
#Logs to Lambda function Execution results
return {
'statusCode': 200,
'message': "Starting Rds instance",
'body': json.dumps(response, default=str)
}
except ClientError as e:
#send logs to cloudwatch
print(e)
message = e
#Logs to Lambda function Execution results
return {
'message': "Script execution completed. See Cloudwatch logs for complete output, but instance starting failed",
'body': json.dumps(message, default=str)
}
# if Rds instance is in running state, It will be stopped
elif status == "available":
try:
#Stopping the Rds instance
response = context.rds_client.stop_db_instance( DBInstanceIdentifier=DBinstance )
#send logs to cloudwatch
print ('Success :: Stopping Rds instance:', DBinstance)
#Logs to Lambda function Execution results
return {
'statusCode': 200,
'message': "Stopping Rds instance",
'body': json.dumps(response, default=str)
}
except ClientError as e:
#send logs to cloudwatch
print(e)
message = e
#Logs to Lambda function Execution results
return {
'message': "Script execution completed. See Cloudwatch logs for complete output, but instance stopping failed",
'body': json.dumps(message, default=str)
}
Currently I am trying to implement a function call that sends failed messages from a converter to a DLQ topic with Kafka. As part of the DLQ message I want to include the exception error that we also log.
the code:
except json.decoder.JSONDecodeError:
log.error('failed to parse json',
topic=msg.topic(),
partition=msg.partition(),
offset=msg.offset()
)
produce_dlq_message(converters.get("DLQ"), msg, error_message)
I need to get the value of that latest log.error() call and assign it to variable: error_message
I call this exact same function at another exception block but it has a different value in log.error() call so I need something that gets the last/latest error message.
While there might be a way to achieve that with multistructlog, processors and whatnot, I would recommend to take the low-tech route:
try:
...
except json.decoder.JSONDecodeError:
em = {
"event": "failed to parse json",
"topic": msg.topic(),
"partition": msg.partition(),
"offset": msg.offset(),
}
log.error(**em)
produce_dlq_message(converters.get("DLQ"), msg, json.dumps(em))
It means em gets serialized twice, but I think overall the simplicity makes it worth it.
I used this solution in the end.
try:
...
except json.decoder.JSONDecodeError as e:
log.error("failed to parse json",
topic=msg.topic(),
partition=msg.partition(),
offset=msg.offset(),
)
error_message = str(e)
produce_dlq_message(converters.get("DLQ"), msg, error_message)
I'm trying to handle for errors when users are signing up or logging in to my app. The first error I'm trying to handle for is when a user tries to create an account with an email that already exists in the database. I get the following HTTPError:
requests.exceptions.HTTPError: [Errno 400 Client Error: Bad Request for url: https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=] {
"error": {
"code": 400,
"message": "EMAIL_EXISTS",
"errors": [
{
"message": "EMAIL_EXISTS",
"domain": "global",
"reason": "invalid"
}
]
}
}
I want to access the "message": "EMAIL_EXISTS" value in the below but I'm not sure how to do it. I've added the below code but that produces the following error:
error_message = error["error"]["message"]
TypeError: 'HTTPError' object is not subscriptable
import requests
import pyrebase
class CreateAccount():
def create_account(self):
try:
auth.create_user_with_email_and_password(self.email, self.password)
except requests.exceptions.HTTPError as error:
print(error)
error_message = error["error"]["message"]
print(error_message)
After much searching I've found an answer to this problem:
except requests.HTTPError as e:
error_json = e.args[1]
error = json.loads(error_json)['error']['message']
if error == "EMAIL_EXISTS":
print("Email already exists")
I've tried the code you provided in comment which I couldn't make to work. Maybe a version issue of requests module or something else.
However, the code below works in my case:
except requests.exceptions.HTTPError as e:
error_json = e.args[1]
error = json.loads(error_json)['error']['message']
if error == "EMAIL_EXISTS":
print("Email already exists")
Yeah, requests.exceptions.HTTPError instead of requests.HTTPError.
In my GAE application, I have several request handlers that return JSON-formated response. When one of these is called, if an error occurs (exception, or programming error), the output is not JSON: it is the stack trace.
What I need is:
Output without error:
{
"foo" : 1
"bar" : 2
"status" : "OK"
}
Output when an error occurs:
{
"status" : "ERR"
"errorMessage" : "An error occurred!"
}
My question is: What is the best practice to make sure that, in any case, the output will be a JSON-formated response? Of course, a common solution for every request handlers would be great.
Any help would be appreciated.
Sure - use the ereporter class (described here: https://stackoverflow.com/a/4296664/336505), but create a custom BaseHandler that formats your uncaught exceptions as JSON output:
class BaseHandler(webapp.RequestHandler):
def handle_exception(self, exception, debug_mode):
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(etc, etc) # format the exception
If an error occurs, to avoid getting a stack trace or other ugly output, you will need to employ a try ... except: http://docs.python.org/tutorial/errors.html
e.g.
try:
# ... your code ...
except TypeError as e:
# ... do something with this error type
except:
# ... generic exception catchall
# output that JSON response