Skip to content

fix: correct CloudWatch Log Group dependency ordering#45

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
mainfrom
loris.friedel/fix-loggroup-dependency-ordering
Apr 9, 2026
Merged

fix: correct CloudWatch Log Group dependency ordering#45
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
mainfrom
loris.friedel/fix-loggroup-dependency-ordering

Conversation

@LorisFriedel

@LorisFriedel LorisFriedel commented Apr 9, 2026

Copy link
Copy Markdown
Member

Problem

The aws_cloudwatch_log_group.forwarder_log_group resource constructs its name from aws_lambda_function.forwarder.function_name, creating an implicit Terraform dependency that forces the Lambda to be created before its log group. This causes ResourceAlreadyExistsException failures because:

  • AWS Lambda auto-creates log groups. When a Lambda function is invoked, AWS automatically creates /aws/lambda/<function_name> if it doesn't exist. Since Terraform creates the Lambda first (due to the wrong dependency direction), any invocation before Terraform reaches the log group resource causes a conflict.
  • Pre-existing log groups. When adopting existing Lambda infrastructure into a new Terraform state (e.g., via terraform import or state migration), the log group already exists and Terraform's CreateLogGroup call fails.

Root Cause

# main.tf (before fix)
resource "aws_cloudwatch_log_group" "forwarder_log_group" {
  name = "/aws/lambda/${aws_lambda_function.forwarder.function_name}"
  #                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  #                      Creates: log_group → depends_on → lambda
  #                      Correct direction: lambda → depends_on → log_group
}

The dependency is backwards. The log group should exist before the Lambda, not after.

Fix

Two changes that invert the dependency direction:

1. Break the wrong dependency

# Log group name now uses var.function_name directly
name = "/aws/lambda/${var.function_name}"

The resolved string is identical (var.function_name is what aws_lambda_function.forwarder.function_name was set to), but the Terraform dependency edge is removed.

2. Create the correct dependency

# Lambda now explicitly points to the Terraform-managed log group
logging_config {
  log_format = "Text"
  log_group  = aws_cloudwatch_log_group.forwarder_log_group.name
}

This tells both Terraform and the Lambda runtime to use the Terraform-managed log group. Terraform creates the log group first, then the Lambda pointing at it. The Lambda runtime won't auto-create a log group.

Alternative considered: depends_on

An alternative is to add depends_on = [aws_cloudwatch_log_group.forwarder_log_group] to the Lambda resource (combined with change 1.). This also fixes the Terraform dependency ordering.

I preferred logging_config for two reasons:

  1. AWS-level protection. depends_on only fixes the Terraform graph — Lambda can still auto-create the log group if invoked in edge cases (e.g., log group deleted out-of-band, or external triggers firing during a destroy-recreate cycle). logging_config tells the Lambda runtime itself to use the specified log group, preventing auto-creation at the AWS API level.

  2. Idiomatic Terraform. The reference to aws_cloudwatch_log_group.forwarder_log_group.name inside logging_config creates an implicit dependency through the resource graph, which is the standard Terraform pattern. Explicit depends_on is recommended only as a last resort since it forces Terraform to defer reading the depended-on resource until apply time.

That said, depends_on is a simpler change with a smaller surface area. If logging_config causes any unforeseen issue during rollout, switching to depends_on is a safe fallback.

Impact on existing deployments

Resource Effect
Log group No diff — name resolves to the same string
Lambda In-place update adding logging_config (not a replacement)
Behavior log_format = "Text" preserves existing default
Provider logging_config requires >= 5.32.0; module already requires >= 6.21

Testing

All 54 existing terraform test cases pass.

The log group's `name` attribute referenced
`aws_lambda_function.forwarder.function_name`, creating an implicit
dependency that forced the Lambda to be created BEFORE the log group.
This caused `ResourceAlreadyExistsException` failures when:
- Migrating accounts between deployment patterns (e.g. per-account
  configs to herds of accounts), where orphaned log groups from
  previous deployments collide with the new Terraform state.
- Destroy-and-recreate scenarios where the Lambda is replaced and
  external triggers invoke it before Terraform recreates the log group.

Two changes fix this by inverting the dependency direction:

1. Log group `name` now uses `var.function_name` directly instead of
   referencing the Lambda resource. This breaks the wrong-direction
   implicit dependency. The resolved string is identical since
   `aws_lambda_function.forwarder.function_name` was already set to
   `var.function_name`.

2. A `logging_config` block on the Lambda explicitly points it at the
   Terraform-managed log group. This creates the correct dependency
   (Lambda depends on log group) and tells the Lambda runtime to use
   the specified log group rather than auto-creating one.

For existing deployments, this is a non-breaking in-place Lambda update
(adding the `logging_config` attribute). The log group shows no diff
since the name resolves to the same value. `log_format = "Text"`
preserves the existing default Lambda logging behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@LorisFriedel
LorisFriedel marked this pull request as ready for review April 9, 2026 08:01
@LorisFriedel
LorisFriedel requested a review from a team as a code owner April 9, 2026 08:01
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit cfb345d into main Apr 9, 2026
5 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the loris.friedel/fix-loggroup-dependency-ordering branch April 9, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants