Runtime Error Handling in AWS Lambda

AWS Lambda offers some powerful resources for running serverless applications. It enables developers to create code without having to worry about the headaches of running and managing servers in the cloud. 

However, with these remote processes, it can be a bit difficult to track errors. On a local or remote system, a developer can see verbose text associated with errors by logging into the system itself (via ssh or other methods), making it relatively easy to track down and solve problems. On Lambda, because there is no server running, errors can just occur, and the application may stop due to a timeout or another reason without providing a clear message. When a Lambda instance errs, it can be difficult to track.   The function itself is gone, but errors and logs remain. So, how do you find errors within AWS Lambda? 

This guide will go over a few methods for detecting, tracking, and (with some luck) solving some errors that occur when running in the Lambda environment.

3 Ways Lambda Fails

Most of the time when Lambda fails, it does so because of the following:

Unhandled Exceptions – these are cases where an invalid input is received, there is an error associated with an API, or there’s simply a coding error.

Timeouts – these can occur when your Lambda code runs longer than a specified timeout duration. One can set these timeouts to up to 5 minutes; however, the default case is 6 seconds. 

Memory errors – If Lambda runs out of memory for a task, it will kill the function during the runtime and typically return an error which states, “Process exited before completing request.”

In each of these cases, Lambda may attempt to retry, but how it reties depends on the reason for the error. 

The Various Ways Lambda Retries

Synchronous

For synchronous events, such as through the API gateway, retries are re-triggered by the service that called the function. In other words, the responsibility for restarting an application needs to be done outside of Lambda. In most cases, if the problem is simply due to a system hiccup (external temporal issue, like networking blips), it should automatically rerun successfully. If it does not, this means that there is an error in the originating application, which should be addressed.

Asynchronous

However, for most uses of Lambda, communication with applications is occurring asynchronously. In these cases, the application is no longer present to take care of the failure that occurs, so AWS will typically attempt to handle these on its own. It will retry this multiple times. If it fails after a couple of attempts, the error message will be sent to AWS’s dead letter queue, where the log file can be monitored.

Streaming

The third type of error in Lambda is associated with streaming events.

In these cases, Lambda will attempt to run the application repeatedly until the data has either processed successfully or the information expires. One thing that is common with each of these is that Lambda simply keeps trying until success or a specified failure limit has been met. Lambda will not accept any new input from an action until this condition has been satisfied.

Error Handling in AWS Lambda

Most Errors can be retrieved from the log files. These can typically be found in CloudWatch by opening the Lambda console functions. From here, you can choose your specific function that is erring, and then choose “monitoring.”  Once you’re in monitoring, you can access individual log files by clicking on “View Logs in Cloudwatch.”

Below are some examples of types of errors one can retrieve from Lambda. 

ServiceError enables you to retrieve all errors directly from Lambda


# rescue all errors from AWS Lambda
begin
  # do stuff
rescue Aws::Lambda::Errors::ServiceError
  # ...
end

If you need to retrieve errors for specific error classes, use individual exceptions. For example:


begin
	# do stuff
rescue Aws::Lambda::Errors::CodeStorageExceededException
	# ...
end

Errors are returned in JSON format. 

For instance, the following code:


def handler(event:, context:)
	puts "Processing event..."
	[1, 2, 3].thing("two")
	"Success"
end

will generate the following error


{
  "errorMessage": "no implicit conversion of String into Integer",
  "errorType": "Function",
  "stackTrace": [
    "/var/task/function.rb:3:in `thing'",
    "/var/task/function.rb:3:in `handler'"
  ]
}

Common Issues

One common issue many users face when first deploying to Lambda is the dreaded “missing gem/library/package” error. This type of error is caused by various missing libraries or files. 

Here’s an example of one of these types of errors:


"errorType": "Init\u003cLoadError\u003e",
"errorMessage": "Error loading the 'postgresql' Active Record adapter. Missing a gem it depends on?
libruby.so.2.5: cannot open shared object file: No such file or directory -
/var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.3/lib/pg_ext.so"

This particular error can be remedied by rebuilding the gems in the Ruby library to install the correct bundle.

Debugging Functions Locally

By using the Serverless framework and VS Code, one can mimic Lambda’s behavior on a local machine. All you need to do is use the “invoke local” command.   

You may wish to install serverless as a dev dependency to both allow other developers to be able to make use of the functionality, but also to prevent incompatibility issues.

Conclusion

The use of AWS Lambda can help reduce the large amount of server overhead required to run complex applications. The biggest challenges occur when trying to monitor any errors during the process. Once you understand the types of errors that Lambda can produce, use tools like Airbrake Error Monitoring to ensure things run smoothly. 

Monitor Your App Free for 30 Days

Discover the power of Airbrake by starting a free 30-day trial of Airbrake. Quick sign-up, no credit card required. Get started.