Task timed out after 3.01 seconds

AWS Lambda VPC Timeout: NAT Gateway Missing Fix

Server & Cloud Intermediate 👁 0 views 📅 May 26, 2026

Your Lambda function times out when connected to a VPC without internet access. This guide walks you from quick timeout increase to proper NAT gateway setup.

Why This Happens

Your Lambda function is attached to a VPC with private subnets—no public IP, no NAT gateway. Lambda runs inside the VPC but can't reach the internet. If your code calls an external API, downloads a package, or hits AWS services over the public endpoint, it hangs until the default 3-second timeout kills it. I've seen this trip up teams deploying serverless apps that need to call Stripe, Twilio, or even S3 buckets in a different region.

The 30-Second Fix: Increase Timeout or Remove VPC

This isn't the real solution, but it'll stop the error while you plan. Go into Lambda console, increase the timeout from 3 seconds to 30 or 60. That buys you time to see the actual error in CloudWatch logs—usually connect() timed out. If your Lambda doesn't need VPC access (e.g., it's not touching an RDS database or ElastiCache), just remove the VPC configuration entirely. Lambda will get a public IP via the AWS network and can reach the internet no problem.

# Check logs in CloudWatch
aws logs get-log-events --log-group-name /aws/lambda/your-function-name --log-stream-name "$(aws logs describe-log-streams --log-group-name /aws/lambda/your-function-name --order-by LastEventTime --descending --max-items 1 --query 'logStreams[0].logStreamName' --output text)" | grep -i "timeout\|error"

If you see connect() timed out, you've confirmed the issue. No VPC fix needed? Stop here. Otherwise, move to the moderate fix.

The 5-Minute Fix: Add VPC Endpoints for AWS Services

If your Lambda only talks to AWS services (S3, DynamoDB, SQS, etc.), you don't need a NAT gateway. Add VPC endpoints. This keeps traffic inside AWS's network—faster, cheaper, and no internet needed. Go to VPC console, create endpoints for each service your Lambda hits. For example:

  • com.amazonaws.us-east-1.s3 – Gateway endpoint (free, no extra cost)
  • com.amazonaws.us-east-1.dynamodb – Gateway endpoint
  • com.amazonaws.us-east-1.execute-api – Interface endpoint (charges per hour)

Attach each endpoint to the same subnets your Lambda uses. Update the route table: for Gateway endpoints, add a route to the endpoint's prefix list. For Interface endpoints, DNS resolves to a private IP automatically. Test your Lambda—it should connect now. This fix saved me when a client's Lambda kept timing out hitting S3 from a private subnet. No NAT needed.

The 15-Minute Fix: Deploy a NAT Gateway

If your Lambda calls third-party APIs or non-AWS services, VPC endpoints won't help. You need a NAT gateway in a public subnet. Here's the step-by-step:

  1. Create an Internet Gateway (IGW) – Attach it to your VPC if not already there.
  2. Create a public subnet – A subnet with a route to the IGW. Example: 10.0.1.0/24.
  3. Create a NAT Gateway – In VPC console, place it in the public subnet. Allocate an Elastic IP. This costs ~$0.045/hour plus data processing fees.
  4. Update route tables – For your Lambda's private subnet, add a route: 0.0.0.0/0 -> nat-gateway-id.
  5. Test – Invoke your Lambda. It should now reach the internet.

Pro tip: NAT Gateway vs NAT Instance? Always use the gateway. NAT instances are old, require patching, and have lower throughput. The gateway scales automatically up to 45 Gbps.

One gotcha: Lambda execution role needs ec2:CreateNetworkInterface permission. Add this to your IAM policy if you haven't:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateNetworkInterface",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DeleteNetworkInterface"
      ],
      "Resource": "*"
    }
  ]
}

Costs add up—NAT gateway plus data transfer. For high-traffic Lambdas, consider VPC endpoints where possible, or restructure your code to avoid internet calls. I've seen teams move external API calls to a sidecar container in ECS just to ditch the NAT cost.

Testing and Verification

After applying any fix, curl a public URL from your Lambda to confirm:

import urllib.request
import json

def lambda_handler(event, context):
    try:
        with urllib.request.urlopen('https://api.ipify.org?format=json', timeout=5) as response:
            data = json.loads(response.read())
            return {"status": "Success", "public_ip": data["ip"]}
    except Exception as e:
        return {"status": "Failed", "error": str(e)}

Run this test. If you get a public IP, the fix worked. If it times out again, double-check your route table points to the NAT gateway and not the IGW for private subnets. Common mistake: routing private subnets to the internet gateway—that only works for public subnets. Also verify security groups allow outbound HTTPS (port 443) and HTTP (port 80) to 0.0.0.0/0. Network ACLs are stateless—add inbound ephemeral ports (1024-65535) from 0.0.0.0/0 for return traffic.

When to Skip the NAT Gateway Entirely

Honestly, if you can avoid VPC altogether, do it. AWS Lambda functions that don't need VPC resources run faster and cost less because there's no ENI setup overhead. I've rewritten RDS-dependent apps to use DynamoDB or Aurora Serverless just to cut out the VPC complexity. If you're stuck with VPC, VPC endpoints are your best bet—they're cheaper and simpler than NAT.

Was this solution helpful?