What it means
By default a Lambda function runs outside your VPC, on AWS-managed networking with unrestricted outbound internet access. Attaching it to a VPC changes that completely: the function gets an elastic network interface in your subnets, and from that moment its connectivity is exactly what your routing tables, NAT configuration and security groups permit — no more.
ETIMEDOUT is what the resulting dead end looks like. It is not a refusal. A refused connection produces ECONNREFUSED almost instantly, because something answered and declined. A timeout means the packets went out and nothing ever came back, which is the signature of a missing route or a security group silently dropping traffic. That silence is why the error is so uninformative about its own cause, and why the address in the message is the most useful thing in it.
The detail that catches almost everyone is that AWS service endpoints are public addresses. It is natural to assume that a function calling S3, DynamoDB or Secrets Manager stays "inside AWS" and needs no internet route. It does not: without a NAT gateway or a VPC endpoint for that specific service, those calls leave the subnet and go nowhere. And because each interface endpoint covers one service, a function can reach S3 through a gateway endpoint perfectly while timing out on Secrets Manager, which looks like a bug in one particular call rather than a topology gap.
The last thing worth knowing is that you often will not see this error at all. Most SDK and HTTP clients default to connect timeouts far longer than a typical Lambda's own timeout, so the function is killed before the connection gives up — and you get Task timed out after N seconds with no mention of networking anywhere. Setting a short connect timeout is therefore not just good practice but a diagnostic technique: it converts a silent timeout into a logged error naming the address that could not be reached.
CloudWatch’s Errors metric: Whether CloudWatch’s Errors metric counts this depends on whether the error escaped your handler, which the log line alone does not settle. Counted when the error escapes the handler; code that catches it and returns a degraded response is not counted. Most commonly the Lambda's own timeout arrives first and the invocation is recorded as a timeout instead. LogStitch classified the example below from its log level rather than an extracted error type.
What it looks like in CloudWatch
This is the shape the failure arrives in: the lines of one invocation scattered among everything else the log group received at the same moment.
CloudWatch Logs Before
8 raw lines, in the order CloudWatch delivered them.
LogStitch After
The same lines, grouped into the invocation they belong to.
Error3a8d4f10-5c27-4e69-b013-8f2a6c9d1e75
- 10:31:12.008PLAT
START RequestId: 3a8d4f10-5c27-4e69-b013-8f2a6c9d1e75 Version: $LATEST
- 10:31:12.012INFO
INFO Publishing daily digest recipients=1841
- 10:31:12.118INFO
INFO Resolved api.sendgrid.com to 167.89.118.32
- 10:31:22.204ERROR
ERROR Error: connect ETIMEDOUT 167.89.118.32:443 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16) at sendDigest (/var/task/src/mailer.js:37:11)3 lines - 10:31:22.402PLAT
END RequestId: 3a8d4f10-5c27-4e69-b013-8f2a6c9d1e75
- 10:31:22.402PLAT
REPORT RequestId: 3a8d4f10-5c27-4e69-b013-8f2a6c9d1e75 Duration: 10394.11 ms Billed Duration: 10395 ms Memory Size: 512 MB Max Memory Used: 114 MB Status: error
The panel on the right is generated by running the excerpt on the left through the same parser that powers the free web stitcher — it is what the tool actually produces for this input, not an illustration of it.
How to confirm it from the logs
The distinguishing feature is silence, not refusal. ECONNREFUSED means something answered and said no; ETIMEDOUT means nothing answered at all, which is what a dropped packet looks like. The address in the message tells you where it was going — a private 10.x or 172.16-31.x address is inside your VPC, anything else is being routed out of it.
Check the elapsed time before the error against your client's connect timeout. If the two match, the connection attempt ran its full course without a response. And check whether the invocation reached Task timed out first: with a default SDK timeout longer than the function's, Lambda's clock usually expires before the connection does, and you get a timeout with no error at all.
Causes, most likely first
The function is in a VPC with no route to the internet
Check whether the function has a VPC configuration and whether its subnets are private with a NAT gateway. A Lambda in a VPC has no public IP; a private subnet without a NAT route cannot reach any public endpoint, and the failure is silence rather than an error. This is the single most common cause.
There is no VPC endpoint for the AWS service being called
Look at which AWS service the call targets. AWS service endpoints are public addresses, so a VPC-attached function needs either a NAT route or an interface/gateway endpoint for that specific service. S3 and DynamoDB use gateway endpoints; most others need interface endpoints, each configured individually.
A security group or NACL is dropping the traffic
Check the function's security group egress rules and the destination's ingress rules. A security group that does not allow outbound on the port, or a target whose group does not allow inbound from the function's, drops packets silently — which produces a timeout rather than a rejection.
The destination is unreachable or the address is wrong
Confirm the address in the message is the one you intend. A stale private IP, a hostname resolving to an address in a different VPC, or a database that has moved all produce a connect timeout with no other symptom.
The function was recently attached to a VPC
Check whether the VPC configuration changed around the time the failures started. Adding a VPC configuration removes the function's default internet access entirely, so calls that worked for months begin timing out immediately after a change that looks unrelated.
Fixes
Give private subnets a NAT route, or use VPC endpoints
A VPC-attached function reaches public endpoints only through a NAT gateway in a public subnet. For AWS services specifically, a VPC endpoint is cheaper and keeps the traffic off the internet entirely — a gateway endpoint for S3 and DynamoDB, an interface endpoint for the rest.
yaml# Gateway endpoint — no hourly charge, routes S3 traffic inside the VPC.
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
VpcId: !Ref Vpc
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcEndpointType: Gateway
RouteTableIds: [!Ref PrivateRouteTable]
Set connect timeouts short enough to produce an error
A connect timeout below the function's own timeout converts a silent Lambda timeout into a logged ETIMEDOUT naming the address. That single change is often what makes the problem diagnosable at all.
jsimport { NodeHttpHandler } from "@smithy/node-http-handler";
const client = new S3Client({
requestHandler: new NodeHttpHandler({
connectionTimeout: 2000, // fail fast and name the address
requestTimeout: 5000
})
});
Ask whether the function needs a VPC at all
A Lambda only needs a VPC configuration to reach private resources — an RDS instance, an ElastiCache cluster, an internal service. If it only calls AWS service endpoints and public APIs, removing the VPC configuration restores default internet access and removes an entire class of failure.
bash# Confirm what the function is attached to before changing anything.
aws lambda get-function-configuration \
--function-name orders-fn \
--query 'VpcConfig'
Check the security groups on both ends
Egress from the function's security group and ingress on the destination's must both permit the port. VPC Reachability Analyzer tests the whole path and names the component that blocks it, which is faster than reading rules by hand.
bashaws ec2 create-network-insights-path \
--source "$LAMBDA_ENI_ID" \
--destination "$RDS_ENI_ID" \
--protocol tcp --destination-port 5432
Also seen as
The same underlying failure, worded differently by a different runtime, SDK version, or logging layer. All of these land here — there is no separate page for each phrasing.
Related errors
Errors that show up alongside this one, or that people mistake for it.
References
- AWS Lambda Developer Guide — Connecting outbound networking to resources in a VPC
- AWS Lambda Developer Guide — Troubleshoot networking issues
LogStitch finds this automatically, across every invocation in your account.
Paste a log excerpt into the free web stitcher and see it grouped, classified, and measured in your browser — nothing is uploaded. Or run the Mac app against your own AWS profiles and get the same view over every function you own.