Initializing Enclave...

How to Fix Terraform 'Invalid count argument' Error When Boolean Variable is Null

Threat/Impact Level: HIGH | Exploitability/Downtime Risk: HIGH | Time to Fix: 5 mins

TL;DR

  • What broke: var.enabled is null at plan time; Terraform cannot evaluate null ? 1 : 0 because null is not a valid boolean — the ternary operator does not coerce null to false.
  • How to fix it: Add default = false to the variable definition or guard the expression with coalesce(var.enabled, false) ? 1 : 0.
  • Use our Client-Side Sandbox below to auto-refactor this — paste your .tf block and get corrected HCL instantly without leaking your config.

The Incident (What Does the Error Mean?)

Raw error output:

Error: Invalid count argument

  on main.tf line 12, in resource "aws_instance" "this":
  12:   count = var.enabled ? 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.

── OR ──

Error: Invalid count argument
  The given "count" argument value is null; an integer is required.

Immediate consequence: terraform plan aborts entirely. No diff is generated. If this is in a CI/CD pipeline, the entire apply job fails and no downstream resources are provisioned or destroyed. In a module, every caller of that module is broken simultaneously.


The Attack Vector / Blast Radius

This is a graph evaluation failure, not a runtime error. Terraform builds its dependency graph during the plan phase. The count meta-argument must resolve to a known integer before graph construction completes. When var.enabled is null:

  1. The ternary null ? 1 : 0 cannot short-circuit — Terraform's type system treats null as a distinct type, not as false.
  2. The HCL evaluator throws before any resource diff is computed.
  3. Blast radius in a monorepo: If this variable is passed through a root module into 3–4 child modules, every single module call fails. A single misconfigured tfvars file or a missing environment variable in your pipeline can take down the entire terraform apply run across all environments.
  4. Blast radius in Terragrunt stacks: Dependent run_all apply chains halt at the first affected module, leaving your infrastructure in a partial state — some resources created, others not.

This is especially dangerous in auto-apply pipelines (Atlantis, Terraform Cloud) where a null variable passed from a dynamic source (e.g., an SSM parameter, a data source, or a workspace variable not yet set) silently breaks production deployments.


How to Fix It (The Solution)

Root Cause in One Line

HCL's ternary operator condition ? true_val : false_val requires condition to be of type bool. null is type null, not bool. Terraform does not implicitly cast.


Basic Fix — Add a Default to the Variable

This is the correct fix 90% of the time. If the variable has no default, any caller that omits it passes null.

 variable "enabled" {
-  type = bool
+  type    = bool
+  default = false
 }

With default = false, omitting var.enabled in a tfvars file or module call no longer produces null — it resolves to false, and false ? 1 : 0 evaluates cleanly to 0.


Enterprise Best Practice — Defensive Null Guard at the count Expression

When you cannot change the variable definition (e.g., it lives in a shared module owned by another team, or null is a semantically valid sentinel value meaning "inherit from parent"), guard the expression at the call site.

 resource "aws_instance" "this" {
-  count = var.enabled ? 1 : 0
+  count = coalesce(var.enabled, false) ? 1 : 0

   ami           = var.ami_id
   instance_type = var.instance_type
 }

coalesce(var.enabled, false) returns the first non-null value — so null becomes false, true stays true, false stays false. The downstream ternary then always receives a concrete bool.

Alternative using try() (useful when the entire variable block may be undefined in older Terraform versions):

- count = var.enabled ? 1 : 0
+ count = try(var.enabled, false) ? 1 : 0

Alternative using explicit null check (most readable for code reviewers):

- count = var.enabled ? 1 : 0
+ count = var.enabled != null && var.enabled ? 1 : 0

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

1. Enforce Variable Defaults with tflint

Add the tflint-ruleset-terraform rule terraform_required_providers and enable terraform_typed_variables:

# .tflint.hcl
plugin "terraform" {
  enabled = true
  version = "0.5.0"
  source  = "github.com/terraform-linters/tflint-ruleset-terraform"
}

rule "terraform_typed_variables" {
  enabled = true
}

This flags any bool variable without a default as a warning in your PR pipeline.

2. Checkov Policy — Block Null-Unsafe Count Patterns

# .checkov.yaml
checks:
  - id: CKV_TF_NULL_COUNT
    name: "Ensure count expressions guard against null booleans"
    files:
      - "**/*.tf"

Use a custom Checkov check or OPA/Conftest policy to scan for the pattern count = var\.[a-z_]+ \? without a preceding coalesce or try.

3. OPA/Conftest Policy (Rego)

# policies/no_null_count.rego
package terraform

deny[msg] {
  resource := input.resource[_][_][_]
  count_val := resource.count
  # Flag raw ternary on a variable reference without null guard
  contains(count_val, "var.")
  not contains(count_val, "coalesce")
  not contains(count_val, "try")
  not contains(count_val, "!= null")
  msg := sprintf("Resource count expression '%v' is not null-safe. Wrap with coalesce() or try().", [count_val])
}

4. terraform validate in Every PR

# .github/workflows/tf-validate.yml
- name: Terraform Validate
  run: |
    terraform init -backend=false
    terraform validate

terraform validate catches type mismatches before plan if the variable type is declared as bool and no default is set — it will warn on missing required variables. Pair with -var='enabled=false' as a safe sentinel for validation runs.

5. Workspace / Pipeline Variable Hygiene

In Terraform Cloud / Atlantis, always set a workspace-level default for boolean feature flags. Never rely on the absence of a variable to mean false — Terraform's type system does not share that assumption.

Related Diagnostics

"Part of the Syntax Utility Matrix."

View all 153 Syntax Tools →