Initializing Enclave...

How to Fix 'The condition value is not a valid boolean' in Terraform Variable Validation

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

TL;DR

  • What broke: Terraform's validation block requires its condition attribute to resolve to a strict boolean (true/false). Your expression is returning a string, number, list, or null — Terraform hard-fails at terraform validate / plan.
  • How to fix it: Wrap the offending expression in a boolean-casting function (can(), contains(), length(...) > 0, or a direct comparison operator) so the condition always resolves to true or false.
  • Fast path: Use our Client-Side Sandbox above to paste your variable block and auto-refactor the condition expression instantly.

The Incident (What Does the Error Mean?)

Raw error emitted by terraform validate or terraform plan:

Error: Invalid validation condition

  on variables.tf line 8, in variable "instance_type":
   8:     condition = var.instance_type

The condition value is not a valid boolean. Terraform requires a boolean
true or false value for the condition in a validation block.

Immediate consequence: Terraform exits with a non-zero code. Every downstream stage — plan, apply, CI pipeline, Atlantis run, Spacelift job — is dead on arrival. No state is modified, but no infrastructure ships either. In a GitOps workflow, this blocks the entire merge queue.


The Attack Vector / Blast Radius

This is not a runtime error — it is a schema-level rejection. Terraform's type system evaluates condition at parse/validate time. The blast radius:

  • All environments simultaneously. Because variables.tf is typically shared across dev, staging, and prod workspaces, every workspace using this module fails to plan.
  • Module consumers are blocked. If this variable lives inside a reusable module published to a private registry, every team consuming that module version is broken until a patched version is released.
  • Silent misconfiguration risk. The most dangerous variant is when the condition looks boolean but returns a string like "true" (a Terraform string type, not the boolean true). This passes local syntax checks but fails in strict validation, causing intermittent CI failures that are hard to bisect.
  • can() misuse cascades. Engineers who wrap the entire condition in can() to silence the error without understanding the root cause create a condition that always returns true, effectively disabling the validation entirely — a silent security regression.

How to Fix It (The Solution)

Root Cause Taxonomy

Expression Pattern Actual Return Type Fix
var.some_string string Use contains([...], var.x) or var.x == "value"
regex("pattern", var.x) string (matched text) Wrap in can(regex(...))
length(var.x) number Use length(var.x) > 0
lookup(map, key, null) any / null Use lookup(map, key, null) != null
var.flag where flag is string typed string "true"/"false" Change var type to bool or use var.flag == "true"

Basic Fix — Enum String Validation

variable "instance_type" {
  type        = string
  description = "EC2 instance type"

  validation {
-   condition     = var.instance_type
+   condition     = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type)
    error_message = "instance_type must be one of: t3.micro, t3.small, t3.medium."
  }
}

Basic Fix — Regex Pattern Validation

variable "environment" {
  type = string

  validation {
-   condition     = regex("^(dev|staging|prod)$", var.environment)
+   condition     = can(regex("^(dev|staging|prod)$", var.environment))
    error_message = "environment must be dev, staging, or prod."
  }
}

Why can()? regex() returns the matched string on success and throws an error on no match. can() catches that error and returns false, which is the boolean Terraform needs.


Basic Fix — Numeric Range Validation

variable "replica_count" {
  type = number

  validation {
-   condition     = var.replica_count
+   condition     = var.replica_count >= 1 && var.replica_count <= 10
    error_message = "replica_count must be between 1 and 10 inclusive."
  }
}

Enterprise Best Practice — Composite Multi-Condition Validation with Type-Safe Guards

For production modules, never rely on a single condition. Layer them and use alltrue() for readability and auditability:

variable "cidr_block" {
  type        = string
  description = "VPC CIDR block. Must be a valid /16 to /28 range."

  validation {
-   condition     = var.cidr_block
+   condition = alltrue([
+     can(cidrhost(var.cidr_block, 0)),
+     tonumber(split("/", var.cidr_block)[1]) >= 16,
+     tonumber(split("/", var.cidr_block)[1]) <= 28
+   ])
    error_message = "cidr_block must be a valid CIDR notation between /16 and /28."
  }
}

Why this pattern is production-grade:

  • can(cidrhost(...)) validates the CIDR is syntactically valid before the numeric comparisons run — short-circuits on malformed input.
  • alltrue([...]) makes each sub-condition independently auditable in code review.
  • No condition ever returns a non-boolean type; each sub-expression is a comparison or can() call.

💡 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

Do not let this reach a human code review. Catch it at commit time.

1. terraform validate as a Pre-Commit Hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.88.0
    hooks:
      - id: terraform_validate
      - id: terraform_tflint

terraform validate will catch non-boolean conditions before the branch is pushed.

2. TFLint with the AWS/GCP Ruleset

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

rule "terraform_required_version" { enabled = true }
rule "terraform_typed_variables" { enabled = true }  # catches untyped vars that produce ambiguous condition types

3. Checkov Policy — Enforce Validation Blocks Exist

checkov -d . --check CKV_TF_1 --compact

For custom enforcement, add an OPA/Rego policy to your Conftest suite:

# policies/variable_validation.rego
package terraform.validation

deny[msg] {
  var := input.variable[name]
  validation := var.validation[_]
  # Flag if condition is a bare variable reference (no operator)
  validation.condition == concat("", ["var.", name])
  msg := sprintf("Variable '%s': condition is a bare variable reference, not a boolean expression.", [name])
}
conftest test --policy policies/ plan.json

4. GitHub Actions Gate

# .github/workflows/terraform-validate.yml
name: Terraform Validate
on: [pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "~1.8"
      - run: terraform init -backend=false
      - run: terraform validate
        # Fails the PR if any condition is non-boolean

The rule: terraform validate must be a required status check on your default branch. No exceptions. A non-boolean condition in a shared module is a 30-second fix that becomes a 3-hour incident when it ships to a module registry consumed by 12 teams.

Related Diagnostics

"Part of the Syntax Utility Matrix."

View all 153 Syntax Tools →