---
cuppy_hub: aws
cuppy_path: guides/lambda/debug-failing-function.md
cuppy_section: docs
cuppy_doc: ZV3P-JR3C
cuppy_doc_uuid: 5d395799-40a0-4298-adf2-ed3cb0862c80
cuppy_permalink: https://cuppy.io/aws/d/ZV3P-JR3C
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/guides/lambda/debug-failing-function
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: cf0ac15987dbd6a145f90a34e3369c0897ea98293285c20fc51ab822a40335dd
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Debug a Lambda function that fails, times out or is throttled

**Get the actual error first. Invoke synchronously with `--log-type Tail`, or read the function's log group, and look the message up in `reference/lambda/errors.md`.** Most failures are one of these: the 3-second default timeout, a VPC function with no route out, a missing permission on the execution role, or a missing permission on the function's own policy.

## Step 0: reproduce and read

```
aws lambda invoke --function-name <fn> --cli-binary-format raw-in-base64-out \
  --payload file://event.json --log-type Tail out.json
cat out.json        # the function's return value, or {"errorType","errorMessage","trace"}
aws logs tail /aws/lambda/<fn> --since 30m --follow
# or search a wider window with Logs Insights: reference/cloudwatch/logs-insights-queries.md
```

The response's `StatusCode` is 200 even when the code threw. A **function error** shows as `FunctionError` in the response and an error object in `out.json`. A **service error** (throttle, missing permission, bad payload size) fails the CLI call itself with an exception name and a 4xx/5xx status. Those are different problems.

If the log group does not exist, the function has never run, or its role cannot write logs (missing `AWSLambdaBasicExecutionRole`).

## Ranked checks

### 1. Timeout: `Task timed out after N.NN seconds`

- **Timeout too short.** The default is 3 seconds. Raise it with `aws lambda update-function-configuration --function-name <fn> --timeout 30` (the maximum is 900).
- **The function waits on a network call that never answers.** If the function is attached to a VPC, it has **no internet access and no public IP, even in a public subnet**. Calls to AWS APIs or the internet hang until the timeout. Fix: private subnets with a route to a NAT gateway, or VPC endpoints for the AWS services it calls (`patterns/lambda-in-vpc.md`). Check: `aws lambda get-function-configuration --function-name <fn> --query VpcConfig`.
- **Slow downstream or cold start work.** Log timestamps around each call. Set the SDK client's own timeouts below the function timeout so you get an error instead of a silent timeout.

### 2. Permission denied inside the function

`AccessDenied` or `… is not authorized to perform: <action>` from an SDK call means the **execution role** lacks the action. Add it to the role, not to your user. Find the role with `aws lambda get-function-configuration --function-name <fn> --query Role`. For S3 objects encrypted with KMS, also `kms:Decrypt`. To diagnose further: `guides/iam/fix-access-denied.md`.

### 3. Another service cannot invoke it

`… is not authorized to perform: lambda:InvokeFunction on resource: …` means the **function's resource-based policy** does not allow the caller. That applies to S3, EventBridge, SNS, API Gateway, or another account. Inspect it with `aws lambda get-policy --function-name <fn>`. Fix with `add-permission` or a full policy (`reference/lambda/permissions.md`). For a caller in the same account, an identity policy allowing `lambda:InvokeFunction` is enough.

### 4. Code or packaging

| Symptom | Likely cause |
|---|---|
| `Runtime.ImportModuleError` / `Cannot find module` | Handler setting does not match the bundled file (`index.handler` → `index.mjs` or `index.js` at the zip root), or a dependency was not bundled. UNVERIFIED exact message text. |
| `Runtime.HandlerNotFound` | The file exists but does not export that name. UNVERIFIED exact message text. |
| `Runtime.NodejsExit` | The code called `process.exit()` or the event loop crashed. Return from the handler instead. |
| `Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]` | A custom runtime with no executable `bootstrap` in the package |
| `Runtime exited with error: signal: killed` | Memory exhausted. Raise `--memory-size`. UNVERIFIED exact message text. |

### 5. State and in-flight updates

`ResourceConflictException: … The function is currently in the following state: Pending` means a create or update is still in progress. Use `aws lambda wait function-updated-v2 --function-name <fn>` before the next call. A function stuck `Inactive` or `Failed` reports why in `StateReasonCode`: `aws lambda get-function-configuration --function-name <fn> --query '[State,StateReason,StateReasonCode,LastUpdateStatus]'`. VPC (ENI or subnet) and KMS problems show here.

### 6. Throttling: `TooManyRequestsException` (429)

The account's concurrency is a per-Region quota shared by all functions. A function with **reserved concurrency** cannot exceed it, and reserved concurrency of **0** stops all invocations, sometimes set deliberately to break a loop. Check with `aws lambda get-function-concurrency --function-name <fn>` and `aws lambda get-account-settings`. Each function can also only add 1,000 execution environments every 10 seconds, so a sudden burst throttles even below the quota. Asynchronous sources (S3, SNS, EventBridge) retry throttled events. Synchronous callers must retry with backoff.

### 7. Runs repeatedly or never stops

- **Asynchronous retries.** Failed async invocations are retried up to two more times. Make the handler idempotent, and configure a failure destination or dead-letter queue to catch what still fails.
- **Recursive loop.** For example, a function that writes to the bucket or queue that triggers it. Lambda detects some loops and stops them (`RecursiveInvocationException`). To stop one immediately: `aws lambda put-function-concurrency --function-name <fn> --reserved-concurrent-executions 0`. Then fix the trigger.

### 8. Payload too big

`RequestTooLargeException` (413) means the request exceeds the payload limit: 6 MB synchronous, 1 MB asynchronous. A **response** over 6 MB fails the synchronous invocation. Pass large data through S3 and send a reference.

## Environment variables encrypted with a disabled key

`KMSDisabledException: Lambda was unable to decrypt the environment variables because the KMS key used is disabled` means the customer managed key on the function's environment is disabled. Re-enable the key, or update the function to use another key. The execution role needs `kms:Decrypt` on the key.

## Still stuck

Compare against a minimal handler that only returns `{ ok: true }`, with the same role, VPC and memory. If that fails too, the problem is configuration, not code.

Related: the invoke call and its retries (`reference/lambda/invoke.md`); runtime deprecation dates and fixed limits (`reference/lambda/runtimes-and-limits.md`); building and deploying TypeScript (`guides/lambda/deploy-function.md`).


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 131 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/aws/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
