What it means
There are two kinds of permission a Lambda function needs, and conflating them is what produces this error. The first is obvious: whatever your code calls — DynamoDB, S3, SQS — has to be permitted. The second is easy to miss entirely, because it covers calls your code never makes.
When a function is attached to a VPC, Lambda has to create an elastic network interface in your subnets to give the execution environment a path into your network. It makes that EC2 call using your function's execution role, not as a service principal with its own permissions. So the role needs ec2:CreateNetworkInterface even though there is no EC2 code anywhere in your project, and the absence of it stops the function before it exists.
The most common way in is adding a VPC configuration to a function that already worked. Attaching the VPC does not update the role, so a function that ran happily for months starts failing every invocation immediately after a change that looks like it only touched networking. Nothing about the code changed and nothing about the permissions your code needs changed — the role simply now needs permissions for something Lambda does on its behalf.
Three EC2 actions are involved and all three are needed, which matters because granting only the first appears to work. Lambda creates the interface when it scales up, describes it while managing it, and deletes it when the function is removed or its VPC configuration changes. A role with only CreateNetworkInterface succeeds at the thing you tested and leaves orphaned interfaces behind later, at a moment far removed from the deploy that caused it. AWSLambdaVPCAccessExecutionRole is the managed policy that contains the correct set, and using it is safer than assembling the list by hand.
CloudWatch’s Errors metric: The error escaped your handler, so Lambda reports the invocation as failed and CloudWatch’s Errors metric counts it. Lambda cannot create the execution environment, so the invocation fails and CloudWatch counts it. LogStitch classified the example below from its log level rather than an extracted error type, because the platform writes this as a plain error line.
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
4 raw lines, in the order CloudWatch delivered them.
LogStitch After
The same lines, grouped into the invocation they belong to.
Error5f0b7d31-8c46-4a29-b715-3d9e2a6c4f80
- 13:18:22.114PLAT
START RequestId: 5f0b7d31-8c46-4a29-b715-3d9e2a6c4f80 Version: $LATEST
- 13:18:22.204ERROR
ERROR The provided execution role does not have permissions to call CreateNetworkInterface on EC2
- 13:18:22.402PLAT
END RequestId: 5f0b7d31-8c46-4a29-b715-3d9e2a6c4f80
- 13:18:22.402PLAT
REPORT RequestId: 5f0b7d31-8c46-4a29-b715-3d9e2a6c4f80 Duration: 288.11 ms Billed Duration: 289 ms Memory Size: 512 MB Max Memory Used: 78 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 message names the exact EC2 action that was refused, and there are three that matter: CreateNetworkInterface, DescribeNetworkInterfaces and DeleteNetworkInterface. All three are needed, and a role granted only the first will work until Lambda tries to clean up.
This appears before any of your own output, because it happens while the execution environment is being built. It also appears at deploy time in CloudFormation and CLI output, so seeing it in both places is expected rather than two separate problems.
Causes, most likely first
The role does not have the VPC access managed policy
List the policies attached to the execution role and look for AWSLambdaVPCAccessExecutionRole. Adding a VPC configuration to an existing function does not update its role, so a function that worked fine outside a VPC fails immediately after being moved into one.
A hand-written policy grants only a subset of the three actions
Read the action list in the role's inline policy. Granting CreateNetworkInterface alone is common and superficially works, because the failure only appears later when Lambda tries to describe or delete the interface.
A permissions boundary or SCP blocks the EC2 actions
Check for a permissions boundary on the role and for service control policies in the organization. An explicit deny overrides the managed policy, so the role can look correct in the console and still be refused.
The resource scope on the policy is too narrow
Look at the Resource element. These EC2 actions do not support resource-level permissions in the way people expect, so a policy scoping them to a particular subnet or interface ARN denies calls that a * resource would allow.
Fixes
Attach the managed policy AWS provides for exactly this
AWSLambdaVPCAccessExecutionRole contains the three EC2 actions plus the CloudWatch Logs permissions every function needs. Attaching it is the intended answer and avoids getting the action list subtly wrong by hand.
yamlResources:
FunctionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: { Service: lambda.amazonaws.com }
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
If you write the policy by hand, grant all three actions
Lambda creates the interface when it scales up, describes it while managing it, and deletes it when the function is removed or reconfigured. Missing any one leaves a failure that surfaces at a different moment from the deploy that caused it.
json{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
"ec2:AssignPrivateIpAddresses",
"ec2:UnassignPrivateIpAddresses"
],
"Resource": "*"
}
Confirm what the role actually has before redeploying
Listing the attached policies takes seconds and distinguishes a missing policy from a permissions boundary denying one that is present.
bashaws iam list-attached-role-policies --role-name orders-fn-role
aws iam get-role --role-name orders-fn-role \
--query 'Role.PermissionsBoundary'
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 — Lambda execution role
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.