Lambda Not Logging to CloudWatch: The IAM Fix

Logeshwaran
—

If you invoke an AWS Lambda function and no log group — or no log stream inside an existing log group — shows up in CloudWatch Logs, the cause is almost always one thing: the function's execution role doesn't have permission to write logs, and Lambda fails silently instead of throwing an error you'd notice. Fix that first, then check four other causes: a policy scoped to the wrong log group, a log group that got deleted and never came back, logs quietly redirected somewhere else by Advanced Logging Controls, or you simply checking the wrong region before the logs finish arriving. Here's the part that catches almost everyone off guard: a Lambda function can invoke perfectly, return a clean 200 response, and keep doing that for months, while its logging has been broken the entire time — because whether your function runs and whether it can write logs are two completely separate permission checks, and only one of them affects whether your code appears to "work."

⚡ Quick Answer

• Check the execution role first → open the function's Configuration > Permissions tab and confirm the role has logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents, usually via the AWSLambdaBasicExecutionRole managed policy.

• No AdSense/error, but still nothing? Check that the role's permissions aren't scoped to a different log group ARN than /aws/lambda/<your-function-name>.

Full walkthrough of all five causes below, starting with the missing-permission cause. Logs can take 5–10 minutes to appear even when everything is configured correctly.

Jake found out the hard way. He'd wired up a small Lambda function to watch his phone shop's stock database and email him whenever a popular model dropped below five units on hand, so he could reorder before he ran out. The function ran on a schedule, quietly, for weeks. Then a corporate customer tried to place a $1,800 order for fifteen units of one phone, and Jake didn't have them, and didn't know he was low, because the reorder email had never once been sent. When he opened the Lambda console to see what had gone wrong, the "Test" button showed a perfectly successful invocation. The function was working. It just wasn't logging anything, and nobody had noticed for a month.

"That's the part that gets me," Jake said. "It ran. The green checkmark was right there. How is a function 'working' and 'silently broken' at the same time?"

Ethan pulled up the architecture diagram before answering. "Because Lambda and CloudWatch Logs are two separate services having two separate conversations with your function's role," he said. "One conversation is 'may this code run, and may it touch the resources it's written to touch' — that's what determines whether you get a 200 or an error. The other conversation is 'may this role create a log group, create a log stream inside it, and push log events into that stream' — and that permission has nothing to do with whether your code executes. Your function can do everything it was written to do and never once succeed at that second conversation. It just doesn't tell you that, because from the runtime's point of view, a failed log write isn't your function's problem to report."

The Five Real Causes, at a Glance

By default, AWS Lambda automatically captures logs for every invocation and sends them to CloudWatch Logs, provided the function's execution role has the necessary permissions, storing them in a log group named /aws/lambda/<function-name>. That single sentence hides almost every cause of "no logs showing up" — it's a chain of four conditions (permission, correct group, group exists, and log format/destination not redirected) plus one condition that's just about where and when you're looking. Here's the order to check them in, cheapest fix first:

Cause How common Fix effort
1. Role has no log permissions Most common Attach one managed policy
2. Permissions scoped to wrong log group ARN Common on custom, least-privilege roles Edit the policy resource
3. Log group was deleted manually Occasional, after "cleanup" Recreate the group or re-invoke
4. Advanced Logging Controls point elsewhere Occasional, after config changes Check the log group setting
5. Wrong region, timing, or console tab Surprisingly common Wait, or look in the right place

Cause 1: The Execution Role Has No Logging Permission

Every Lambda function must have an execution role — an IAM role that Lambda assumes when it runs your function, giving it temporary credentials for whatever the attached policies allow. At a minimum, that role must have access to CloudWatch, because Lambda functions log to CloudWatch Logs by default, and that access has to be granted explicitly. It is not automatic just because the function exists.

If you created the function through the Lambda console and picked "Create a new role with basic Lambda permissions," you're fine — the console attaches the AWSLambdaBasicExecutionRole managed policy for you, which grants exactly the three actions logging needs. Where this breaks is everywhere else: functions created through Infrastructure as Code (CloudFormation, Terraform, CDK, SAM) where someone wrote a custom role and forgot the logging statement; functions where an existing role got reused from another project that never needed logs; and functions built with a "least privilege from day one" policy that only lists the permissions the developer thought they'd need.

🙋‍♂️ Jake's Reality Check

"I used the console. Doesn't that mean it's automatically fine?"

Only if you picked "Create a new role." If you selected "Use an existing role" — which people do the second time they build a function, to avoid role sprawl — you inherited whatever that role already had, and it may never have had logging permissions in the first place.

The three permissions your role needs are logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents. Lambda uses the first to create the /aws/lambda/<function-name> log group the very first time your function runs, the second to create a new stream inside it for each batch of execution environments, and the third to actually push your log lines and the automatic START/END/REPORT lines into that stream. Miss any one of the three and logging fails somewhere in that chain — usually completely, sometimes partially, which is confusingly worse.

✅ Why this is the one to use

Attach the AWS managed policy AWSLambdaBasicExecutionRole rather than hand-typing the three permissions yourself. It's maintained by AWS, it's exactly scoped to what Lambda logging needs, and it's the same policy the console attaches automatically — using it keeps your hand-built roles consistent with what a fresh console-created function would already have.

Cause 2: The Role Has Permissions — For a Different Log Group

This one is more frustrating than Cause 1, because it looks identical from the outside — no logs — but you'll find the role clearly has logging permissions when you check. The problem is what those permissions apply to. If the IAM policy attached to your role limits log creation or log stream permissions to specific log group ARNs rather than a wildcard, your logs won't appear where you expect unless the resource in the policy matches the actual log group your function writes to.

This happens most often after a rename. Someone renames a Lambda function from process-orders to process-orders-v2, and Lambda dutifully starts trying to write to a new log group, /aws/lambda/process-orders-v2 — but the IAM policy still only grants access to arn:aws:logs:*:*:log-group:/aws/lambda/process-orders:*, the old name. The role has real, working logging permissions. They're just pointed at a log group that no longer matches.

How to check for a scoped-permission mismatch

Open the role in the IAM console, find the inline or attached policy that grants logs:* actions, and look at the Resource field. If it's "Resource": "arn:aws:logs:*:*:*", that's unrestricted and this isn't your problem. If it names a specific log group ARN, compare it character-for-character against your function's actual log group name, which is always /aws/lambda/ followed by the exact, current function name.

Cause 3: The Log Group Was Deleted and Nothing Recreated It

Somebody, at some point, probably cleaned up. CloudWatch Logs charges by ingestion and storage, log groups default to "Never Expire" retention, and a console full of stale log groups from deleted or renamed functions is genuinely annoying to look at. So a group gets deleted manually — and then the function that owned it runs again, and the console shows a big red warning that the expected log group does not exist, even though the function's execution role clearly lists permission to create and write to it.

This is confusing because it looks like a permissions failure, but it's a sequencing one. If the IAM policy limiting the role to certain log groups was written when the log group already existed, and something downstream also relies on that group being present without logs:CreateLogGroup permission included, the automatic recreation can fail. The most reliable fix is to explicitly create the log group again rather than assume Lambda will recreate it on the next invocation:

  1. Open a terminal with the AWS CLI configured for the right account and region.
  2. Run aws logs create-log-group --log-group-name "/aws/lambda/your-function-name", matching the function name exactly.
  3. Invoke the function once, either from the console's Test tab or with aws lambda invoke.
  4. Wait a few minutes, then confirm a new log stream appears inside the group.

⚠️ What this actually breaks

Deleting a log group deletes its history permanently. There's no undo, no trash bin, no recovery window. If that group had months of production troubleshooting data in it and someone deletes it as "cleanup" without exporting it first, that history is simply gone. Before deleting any log group tied to a live function, export it or confirm nobody needs it.

Cause 4: Advanced Logging Controls Are Quietly Redirecting Your Logs

Lambda's Advanced Logging Controls let you configure, for supported runtimes, a log format (plain text or structured JSON), a log level for JSON logs, and — this is the one that trips people up — which CloudWatch log group the function sends logs to at all. It's entirely possible for a function to be logging perfectly well, just not to the /aws/lambda/<function-name> group you're staring at.

This is easy to end up in by accident. If someone was experimenting with aggregating logs from several functions into one shared group — a legitimate pattern, useful for running one CloudWatch Logs Insights query across a whole pipeline — and set the custom log group during testing, that configuration persists after the experiment ends unless someone explicitly reverts it.

Setting Default Where to check it
Log format Plain text Configuration > Monitoring and operations tools > Edit
Log group destination /aws/lambda/<function-name> Same panel, "Log group" field
Application log level INFO (JSON format only) Same panel

If you find a custom log group name in that field, that's where your logs have been going all along. Open that group directly instead of the default one, or change the setting back if the redirection wasn't intentional.

Cause 5: You're Looking in the Wrong Place, Region, or Time Window

Before assuming anything is broken, rule out the boring explanation. It may take 5 to 10 minutes for logs to show up after a function invocation — checking thirty seconds after a Test run and concluding "nothing's there" is one of the single most common false alarms in this whole troubleshooting process. Give it time, then check again.

Beyond timing, three other simple mismatches account for a lot of "missing" logs: checking the CloudWatch console in a different AWS Region than the one your function actually runs in, having the wrong AWS account active if you work across multiple accounts, and — easy to laugh at until it happens to you — checking a log group for a similarly-named function instead of the one you actually invoked, which is common once you have more than a handful of functions with overlapping names like process-orders and process-orders-backup.

The VPC Myth: Do You Need a NAT Gateway to Log?

"Wait, so half the internet is telling me to attach a NAT gateway to fix this?" Jake asked, after reading three different forum threads. That advice is wrong for the ordinary case, and it's worth being direct about why.

Standard Lambda runtime logs are delivered by Lambda's own platform when the execution role has the right permissions — that delivery path doesn't route through your function's VPC networking at all, even if your function itself is attached to a VPC. A function sitting in a private subnet with zero internet access still ships its standard logs to CloudWatch just fine, because the platform, not your function's network interface, is the one talking to CloudWatch Logs.

✅ When VPC networking genuinely matters for logging

There's one real exception: if you're using Lambda Managed Instances, or your function code or an extension calls the CloudWatch Logs API directly from inside a VPC — rather than relying on Lambda's automatic log capture — that direct call does need a network route to the CloudWatch Logs endpoint, either through a NAT gateway or an interface VPC endpoint for the logs service. If your function just uses console.log, print, or a standard logging library and lets Lambda capture output automatically, none of this applies to you, and a NAT gateway will not fix a permissions problem.

How to Check Lambda Logs in AWS, Step by Step

There are four ways to view Lambda logs — the Lambda console, the CloudWatch console, the AWS CLI, or the CloudWatch API — and it's worth knowing all four, because when logs seem "missing," checking the same place twice won't tell you anything new.

  1. Lambda console, fastest for a single recent run: open your function, go to the Monitor tab, then View CloudWatch logs, or run a Test and expand the execution results directly.
  2. CloudWatch console, best for browsing history: go to CloudWatch > Log groups, search for /aws/lambda/ plus your function name, and open the most recent log stream.
  3. AWS CLI, best for scripting or when the console feels slow: run aws logs tail /aws/lambda/your-function-name --follow to stream new log lines as they arrive.
  4. CloudWatch Logs Insights, best for searching across many invocations: from the log group, choose Logs Insights and query by request ID, error text, or time range instead of scrolling streams manually.

The Exact IAM Policy That Fixes This

If you don't need custom permissions beyond logging, the fastest fix is to attach the managed policy rather than write your own:

  1. Open the IAM console and go to Roles.
  2. Find and select your Lambda function's execution role — the exact name is visible on your function's Configuration > Permissions tab.
  3. Choose Add permissions > Attach policies, search for AWSLambdaBasicExecutionRole, select it, and attach it.
  4. Invoke the function again and check the log group after a few minutes.

If you're building the role by hand and want the exact statement instead of the managed policy, this is what it needs to contain:

Action What it does Required?
logs:CreateLogGroup Creates the group on first invocation Yes
logs:CreateLogStream Creates a new stream per execution environment Yes
logs:PutLogEvents Writes the actual log lines Yes

Set the resource to arn:aws:logs:*:*:* for a simple, function-agnostic policy, or scope it to arn:aws:logs:*:*:log-group:/aws/lambda/your-function-name:* if you want it locked to exactly one function's log group — just remember Cause 2 above if you ever rename that function.

What It Looks Like When the Fix Doesn't Work

Attaching the managed policy solves most cases immediately. When it doesn't, the failure usually falls into one of these:

  1. You still see nothing after 15 minutes. Re-check the role name on the function's Permissions tab against the role you actually edited — in accounts with several similarly named roles, it's easy to fix the wrong one.
  2. The log group appears but stays empty. This points back to Cause 4 — the function's log format or destination setting may have been left pointed at a different group even after permissions are correct.
  3. Logs appear for some invocations but not others. Check whether a permission boundary or a Service Control Policy at the AWS Organizations level is intermittently denying the action for certain accounts or regions; an explicit deny anywhere in the policy chain always wins over an allow, no matter how permissive the role itself looks.

That third case is worth naming plainly: if an organization-level Service Control Policy explicitly denies logs:PutLogEvents, no change you make inside the account you're looking at will fix it. You have to go find and fix the SCP itself, which usually means asking whoever manages the AWS Organization, not the account owner.

Where Logs Go Next: Alarms, S3, and Monitoring at Scale

Once logging itself is reliable, most teams want two more things: to be alerted automatically when something goes wrong, and to keep older logs somewhere cheaper than CloudWatch's default storage.

Triggering a Lambda function from a CloudWatch alarm

CloudWatch Alarms can invoke a Lambda function directly as an alarm action, without needing an SNS topic in between, though routing through SNS or EventBridge is still common when you want fan-out to multiple targets, message filtering, or a shared notification pipeline across several alarms. If you want a single alarm to trigger a single automated response, a direct alarm action is the simpler setup; if you want that alarm state change to reach several destinations or be filtered before it does anything, SNS or EventBridge gives you more control.

Sending CloudWatch Logs to S3

Ethan's take: "Don't just leave everything sitting in CloudWatch forever — that's the option nobody actively chooses, it's just what happens by default." Log groups default to Never Expire retention, meaning logs accumulate indefinitely and cost money indefinitely, until someone sets a retention period. Two paths move data to cheaper, longer-term storage: a one-time or scheduled export task, which copies a time range of log data from a log group into an S3 bucket and can take up to 12 hours for the data to become available; or a subscription filter pointed at Amazon Data Firehose, which streams matching log events to S3 continuously and in near real time. Use export tasks for occasional archival or compliance snapshots; use a subscription filter and Firehose if you want every new log event landing in S3 as it happens.

Frequently Asked Questions

How do I check Lambda logs in AWS?

Open your function in the Lambda console and go to the Monitor tab, then choose View CloudWatch logs, or open the CloudWatch console directly and search Log groups for /aws/lambda/ plus your function's name. The AWS CLI command aws logs tail /aws/lambda/your-function-name --follow streams new lines live.

Why does my Lambda function run successfully but show no logs?

Successful invocation and successful log delivery are separate permission checks. Your execution role can be fully able to run your code while completely lacking the logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents permissions logging needs, and Lambda doesn't surface that gap as an invocation error.

How long does it take for Lambda logs to appear in CloudWatch?

Typically 5 to 10 minutes after an invocation. Checking immediately and concluding logging is broken is one of the most common false alarms in this troubleshooting process.

Does my Lambda function need to be in a VPC to write logs?

No. Standard Lambda logging is delivered by the platform, not through your function's VPC network interface, so functions in private subnets with no internet access still log normally. The exception is if your code or an extension calls the CloudWatch Logs API directly from inside a VPC, or you're using Lambda Managed Instances — that direct call does need a network route to the CloudWatch Logs endpoint.

What is the default log group name for a Lambda function?

/aws/lambda/ followed by the exact, current function name. If you renamed the function, the log group name changes to match, which can break IAM policies that were scoped to the old name.

Can I change which CloudWatch log group my Lambda sends logs to?

Yes, through Advanced Logging Controls on the function's Configuration, under Monitoring and operations tools. You can also choose plain text or structured JSON log format, and for JSON format, set an application log level such as INFO, WARN, or ERROR.

What IAM permissions does Lambda need to write logs?

logs:CreateLogGroup, logs:CreateLogStream, and logs:PutLogEvents, most easily granted by attaching the AWSLambdaBasicExecutionRole managed policy to the function's execution role.

What does "log group does not exist" mean in the Lambda console?

It means the expected log group has never been created or was deleted after existing previously. Recreate it with aws logs create-log-group --log-group-name "/aws/lambda/your-function-name" and invoke the function again.

Why did my logs disappear after I deleted a log group?

Deleting a log group deletes its history permanently, with no recovery option. If the function that owned it runs again, Lambda attempts to recreate the group, but if that recreation fails for any permission or sequencing reason, you may need to create it manually before logs resume.

Can I trigger a Lambda function from a CloudWatch alarm?

Yes. CloudWatch Alarms can invoke a Lambda function directly as an alarm action, or route the alarm state change through SNS or EventBridge first if you need fan-out to multiple targets or message filtering.

How do I send CloudWatch Logs to S3?

Use a one-time or scheduled export task for occasional archival, which can take up to 12 hours to complete, or set up a subscription filter to Amazon Data Firehose for continuous, near real-time delivery of new log events into an S3 bucket.

Does deleting a Lambda function delete its logs?

No. The CloudWatch log group is a separate resource from the function itself, so deleting the function leaves its log group and existing log data in place until you delete the log group separately.

Why am I only seeing some of my log lines, not all of them?

Check whether the function's log format is set to JSON with a log level filter such as WARN or ERROR — that setting intentionally drops lower-priority log lines before they reach CloudWatch, which can look like missing logs if you were expecting everything to appear.

What is AWS Lambda, in plain terms?

A serverless compute service that runs your code in response to events — like a file upload, an API call, or a scheduled timer — without you having to provision or manage a server. You upload code, Lambda runs it when triggered, and you're billed for the compute time actually used.

Do I need to pay extra for Lambda logging?

There's no additional charge from Lambda itself for sending logs to CloudWatch, but standard CloudWatch Logs ingestion and storage charges apply to the data once it arrives.

How do I stop CloudWatch Logs from costing so much?

Set an explicit retention period on each log group instead of leaving it at the "Never Expire" default, and consider exporting or streaming older logs to S3, which is substantially cheaper for long-term storage than CloudWatch Logs itself.

For readers preparing for an AWS certification

We have been covering AWS certifications alongside our fixes, so here is a short extra for readers studying for one. If you only came for the fix, you already have it; feel free to skip this part.

Exams that test this topic: Developer – Associate (DVA-C03 from December 1, 2026) • CloudOps Engineer – Associate (SOA-C03).

Here are the exam-style questions this topic tends to raise, with the reasoning you need to answer them:

1. A Lambda function runs but writes nothing to CloudWatch Logs. What permission is usually missing?

The execution role needs logs:CreateLogGroup, logs:CreateLogStream and logs:PutLogEvents, which the managed policy AWSLambdaBasicExecutionRole provides.

2. Which log group does Lambda use by default?

/aws/lambda/<function-name>. Advanced logging controls let you choose a custom log group, JSON format and log levels.

3. Does a function inside a VPC need a NAT gateway to send logs?

No. Lambda delivers logs through the Lambda service, not through the function's VPC network.

4. How do you keep log storage costs under control?

Set a retention period on the log group; the default keeps logs forever.

5. How do you trace slow downstream calls, not just log them?

Enable AWS X-Ray active tracing on the function.

6. How do you get alerted when errors spike?

A CloudWatch alarm on the Errors or Throttles metric, or a metric filter on log patterns.

Exam codes and dates change often. Our AWS certification changes page keeps track of what is current.

Revision note. Written August 2026, covering Lambda's current logging permission model, Advanced Logging Controls, and standard AWS CLI/console workflows. If AWS changes how default execution roles are provisioned or how log group naming works, the specifics here will need a refresh. If you landed on this page after losing something the way Jake nearly did, know that a silent logging gap is one of the most forgivable mistakes in AWS — it's designed to fail quietly, and now you know exactly where to look.

Related