Description
When dd_api_key_secret_arn or dd_api_key_ssm_parameter_name is passed from a resource that is created in the same apply, the module’s count expression becomes unknown at plan time and Terraform errors out.
This happens because the module currently uses:
count = var.dd_api_key_secret_arn == null && var.dd_api_key_ssm_parameter_name == null ? 1 : 0
If either variable is set from another resource in the same plan, its value is unknown during planning, so the count cannot be determined.
Minimal reproducible example
resource "aws_secretsmanager_secret" "dd_api_key" {
name_prefix = "DatadogAPIKey"
description = "Datadog API Key"
}
resource "aws_secretsmanager_secret_version" "dd_api_key_version" {
secret_id = aws_secretsmanager_secret.dd_api_key.id
secret_string = "myapikey"
}
module "datadog_forwarder_secretmanager" {
source = "../../"
# This value is unknown at plan time since the secret is created in the same apply
dd_api_key_secret_arn = aws_secretsmanager_secret.dd_api_key.arn
dd_site = "datadoghq.com"
}
Error
Error: Invalid count argument
on main.tf line 28, in resource "aws_secretsmanager_secret" "dd_api_key_secret":
28: count = var.dd_api_key_secret_arn == null && var.dd_api_key_ssm_parameter_name == null ? 1 : 0
The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this,
use the -target argument to first apply only the resources that the count depends on.
Expected behavior
The module should allow either:
- importing an existing secret/parameter, or
- creating the secret/parameter,
even when the imported value is produced by resources created within the same plan.
Actual behavior
Plan fails because count depends on unknown values.
Notes
Using -target or splitting applies (create secret first, then the module) works but is not ideal. Using future “deferrable” expressions could potentially help, but that is not viable for most users today.
Proposed solutions
Option A (breaking): Remove dd_api_key variable and let callers manage the secret/parameter
Have the module only consume dd_api_key_secret_arn or dd_api_key_ssm_parameter_name.
Callers create and manage the secret/parameter themselves (with full control over KMS, rotation, etc.).
Provide examples for both Secrets Manager and SSM.
Example usage:
resource "aws_secretsmanager_secret" "dd_api_key_secret" {
name_prefix = "DatadogAPIKey-${var.function_name}"
description = "Datadog API Key"
tags = var.tags
}
resource "aws_secretsmanager_secret_version" "dd_api_key_secret_version" {
secret_id = aws_secretsmanager_secret.dd_api_key_secret.id
secret_string = var.dd_api_key
}
module "datadog_forwarder_secretmanager" {
source = "../../"
dd_api_key_secret_arn = aws_secretsmanager_secret.dd_api_key_secret.arn
dd_site = "datadoghq.com"
}
Changes
- Simplest mental model; gives users full control.
- Breaking change for users relying on the module to create the secret.
Option B (breaking): Add explicit boolean “mode” switches
Add mutually exclusive booleans to make the creation path a known plan-time choice (not derived from unknown strings):
use_imported_dd_api_key_secret (default: false)
use_dd_api_key_ssm_parameter_name (default: false)
Use validation to enforce mutual exclusivity and ensure required inputs are set when a mode is chosen.
Changes
- Keeps current behavior.
- Slight behavior change for existing users.
Option C (breaking): Single boolean switch
Add one boolean variable:
variable "dd_api_key_imported" {
description = "If true, the module uses an imported secret/parameter instead of creating one."
type = bool
default = false
}
When dd_api_key_imported = true, users must provide one of:
dd_api_key_secret_arn, or
dd_api_key_ssm_parameter_name.
If dd_api_key_imported = false, the module creates the secret/parameter internally.
Use validation to enforce mutual exclusivity and ensure required inputs are set when this is chosen.
Changes
- Easy migration path from current behavior.
- Slight behavior adjustment; users must now set
dd_api_key_imported explicitly if they import.
My preference
Option A remains the cleanest long-term (callers manage the secret/parameter), as it provides maximum flexibility and decouples responsibilities cleanly.
Description
When
dd_api_key_secret_arnordd_api_key_ssm_parameter_nameis passed from a resource that is created in the same apply, the module’scountexpression becomes unknown at plan time and Terraform errors out.This happens because the module currently uses:
If either variable is set from another resource in the same plan, its value is unknown during planning, so the
countcannot be determined.Minimal reproducible example
Error
Expected behavior
The module should allow either:
even when the imported value is produced by resources created within the same plan.
Actual behavior
Plan fails because
countdepends on unknown values.Notes
Using
-targetor splitting applies (create secret first, then the module) works but is not ideal. Using future “deferrable” expressions could potentially help, but that is not viable for most users today.Proposed solutions
Option A (breaking): Remove
dd_api_keyvariable and let callers manage the secret/parameterHave the module only consume
dd_api_key_secret_arnordd_api_key_ssm_parameter_name.Callers create and manage the secret/parameter themselves (with full control over KMS, rotation, etc.).
Provide examples for both Secrets Manager and SSM.
Example usage:
Changes
Option B (breaking): Add explicit boolean “mode” switches
Add mutually exclusive booleans to make the creation path a known plan-time choice (not derived from unknown strings):
use_imported_dd_api_key_secret(default:false)use_dd_api_key_ssm_parameter_name(default:false)Use validation to enforce mutual exclusivity and ensure required inputs are set when a mode is chosen.
Changes
Option C (breaking): Single boolean switch
Add one boolean variable:
When
dd_api_key_imported = true, users must provide one of:dd_api_key_secret_arn, ordd_api_key_ssm_parameter_name.If
dd_api_key_imported = false, the module creates the secret/parameter internally.Use validation to enforce mutual exclusivity and ensure required inputs are set when this is chosen.
Changes
dd_api_key_importedexplicitly if they import.My preference
Option A remains the cleanest long-term (callers manage the secret/parameter), as it provides maximum flexibility and decouples responsibilities cleanly.