Back to blog

AWS Lambda InvalidEntrypoint Debugging

Nov 28, 2025

awslambdapythondockerdebugging

Runtime.InvalidEntrypoint... but the import works fine?

If you are staring at Runtime.InvalidEntrypoint in CloudWatch, your Docker image looks correct, and python3 -c "import handler" works inside the container, there are three common causes that all produce the same useless error.

Async handlers are not awaited

Lambda does not natively support async handlers. It calls your function, gets a coroutine object, and dies trying to serialize it.

Test locally to see the real error:

docker run -p 9000:8080 your-lambda-image:latest
curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
RuntimeWarning: coroutine 'handler' was never awaited
Unable to marshal response: Object of type coroutine is not JSON serializable

The obvious fix is asyncio.run(), but that creates a new event loop every invocation, killing your httpx clients and connection pools.

Use this decorator instead:

import asyncio
from functools import wraps

def async_handler(func):
    _loop = None

    @wraps(func)
    def wrapper(event, context):
        nonlocal _loop
        if _loop is None or _loop.is_closed():
            _loop = asyncio.new_event_loop()
            asyncio.set_event_loop(_loop)
        return _loop.run_until_complete(func(event, context))

    return wrapper

@other_decorators
@async_handler
async def handler(event, context):
    ...

The loop persists across warm invocations.

Architecture mismatch

Building on an M-series Mac produces ARM64 images. If your Lambda is configured for x86_64, the entrypoint fails immediately with a 3ms init. CloudWatch just says InvalidEntrypoint.

Match your Lambda architecture:

function = _lambda.DockerImageFunction(
    ...
    architecture=_lambda.Architecture.ARM_64,
)

File permissions

Lambda runs non-root. Files copied with restrictive permissions cannot be read:

PermissionError: [Errno 13] Permission denied: '/var/task/handler.py'

Fix in your Dockerfile:

COPY --chmod=644 handler.py ${LAMBDA_TASK_ROOT}/
COPY --chmod=755 shared/ ${LAMBDA_TASK_ROOT}/shared/

TL;DR

InvalidEntrypoint is Lambda's catch-all error. Test locally first, the real error only shows up there.