Skip to content

Fix: Terraform Variable Not Set — No Value for Required Variable

FixDevs ·

Quick Answer

How to fix Terraform 'no value for required variable' errors — variable definition files, environment variables, tfvars files, sensitive variables, and variable precedence.

The Error

Terraform prompts for variables interactively or fails because a required variable has no value:


│ Error: No value for required variable

│   on variables.tf line 1:
│    1: variable "database_password" {

│ The root module variable "database_password" is not set, and has no default value.
│ Use a -var or -var-file command line argument to provide a value for this variable.

Or in CI/CD, Terraform hangs waiting for interactive input:

var.database_password
  Enter a value:
  (waiting indefinitely — no TTY available)

Or a terraform.tfvars file exists but variables are still not being loaded:


│ Error: No value for required variable
│ Variable "aws_region" not set.

# Despite aws_region being in terraform.tfvars

Why This Happens

Terraform variables without default values are required — Terraform must have a value before planning or applying. Variables can be provided through several mechanisms, each with its own precedence and file naming conventions:

  • terraform.tfvars is loaded automatically only if it exists in the current working directory with that exact name.
  • *.tfvars files with other names require -var-file=filename.tfvars to be passed explicitly.
  • TF_VAR_ environment variables are read, but the casing must match exactly (case-sensitive).
  • -var flags on the CLI override all other sources.
  • Module variables aren’t the same as root module variables — variables must be declared and passed explicitly to each module.

Fix 1: Create or Fix terraform.tfvars

The most straightforward fix — create a terraform.tfvars file in the same directory as your .tf files:

# terraform.tfvars — automatically loaded by Terraform
database_password = "secure-password-here"
aws_region        = "us-east-1"
instance_type     = "t3.micro"
project_name      = "my-app"

Verify the file location:

project/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars    ← Must be in THIS directory, not a subdirectory

Running terraform plan or terraform apply from a different directory means terraform.tfvars in the project directory won’t be found.

For multiple environments — use separate .tfvars files and pass them explicitly:

# Development
terraform plan -var-file="environments/dev.tfvars"

# Staging
terraform plan -var-file="environments/staging.tfvars"

# Production
terraform plan -var-file="environments/prod.tfvars"
project/
├── main.tf
├── variables.tf
└── environments/
    ├── dev.tfvars
    ├── staging.tfvars
    └── prod.tfvars

Fix 2: Use Environment Variables

For CI/CD pipelines or when you don’t want values in files, use TF_VAR_ environment variables:

# Set environment variable — Terraform reads TF_VAR_<variable_name>
export TF_VAR_database_password="secure-password"
export TF_VAR_aws_region="us-east-1"
export TF_VAR_instance_count="3"

# Variable names are CASE SENSITIVE
# Variable in variables.tf: database_password (lowercase)
# Environment variable: TF_VAR_database_password (same case)

terraform plan   # Picks up TF_VAR_ variables automatically

In GitHub Actions:

# .github/workflows/deploy.yml
jobs:
  terraform:
    runs-on: ubuntu-latest
    env:
      TF_VAR_database_password: ${{ secrets.DB_PASSWORD }}
      TF_VAR_aws_region: us-east-1
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3

      - name: Terraform Plan
        run: terraform plan
        working-directory: terraform/

Complex types via environment variables — must be HCL/JSON encoded:

# List variable
export TF_VAR_allowed_ips='["10.0.0.1", "10.0.0.2"]'

# Map variable
export TF_VAR_tags='{"Environment":"prod","Team":"backend"}'

# Object variable
export TF_VAR_database_config='{"host":"db.example.com","port":5432,"name":"mydb"}'

Fix 3: Pass Variables via -var Flag

For one-off values or script-based workflows:

# Single variable
terraform plan -var="database_password=my-secret-password"

# Multiple variables
terraform plan \
  -var="aws_region=us-east-1" \
  -var="instance_type=t3.medium" \
  -var="database_password=$DB_PASS"

# Combine with var-file
terraform apply \
  -var-file="environments/prod.tfvars" \
  -var="database_password=$DB_PASS"  # Override specific var

Fix 4: Set Default Values in variables.tf

For non-sensitive variables with reasonable defaults, set them in the variable declaration:

# variables.tf

# Required variable — no default, must be provided
variable "database_password" {
  type        = string
  description = "Master password for the database instance"
  sensitive   = true  # Prevents value from appearing in logs
}

# Optional variable — has a default
variable "aws_region" {
  type        = string
  description = "AWS region for all resources"
  default     = "us-east-1"  # Used if not set elsewhere
}

# Variable with validation
variable "instance_type" {
  type        = string
  description = "EC2 instance type"
  default     = "t3.micro"

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

# Map variable with default
variable "tags" {
  type = map(string)
  default = {
    ManagedBy = "Terraform"
    Team      = "platform"
  }
}

Note: Never set default = "" (empty string) as a workaround for sensitive variables. An empty string is a valid value that will be used — it won’t prompt the user, and it might cause downstream errors (database with no password, etc.). Use sensitive = true without a default to force explicit provision.

Fix 5: Understand Variable Precedence

When the same variable is set in multiple places, Terraform uses this precedence (later overrides earlier):

1. Environment variables (TF_VAR_*)          ← Lowest precedence
2. terraform.tfvars file (auto-loaded)
3. terraform.tfvars.json file (auto-loaded)
4. *.auto.tfvars files (auto-loaded, alphabetical order)
5. -var-file flags (in order specified)
6. -var flags                                ← Highest precedence
# Example — variable "region" set in multiple places:
# TF_VAR_region=us-west-1           (env var — lowest)
# terraform.tfvars: region = "us-east-1"
# -var="region=eu-west-1"           (CLI flag — highest)

# Effective value: eu-west-1 (CLI flag wins)
terraform plan -var="region=eu-west-1"

# Effective value: us-east-1 (tfvars wins over env var)
terraform plan

# Show final variable values
terraform plan -var-file=prod.tfvars  # Look at plan output for variable values

Use *.auto.tfvars for per-workspace defaults:

# These files are auto-loaded in alphabetical order
project.auto.tfvars      # Always loaded
dev.auto.tfvars          # Always loaded (named without environment guard)

# Better: use workspace-specific logic in variables.tf

Fix 6: Handle Sensitive Variables Safely

Sensitive variables (passwords, API keys, certificates) shouldn’t be stored in .tfvars files that could be committed to git:

# variables.tf — declare as sensitive
variable "database_password" {
  type      = string
  sensitive = true  # Terraform redacts this from logs and output
}

variable "api_key" {
  type      = string
  sensitive = true
}

Option 1 — .tfvars file in .gitignore:

# .gitignore
*.tfvars
!terraform.tfvars.example  # Keep the example file committed

# terraform.tfvars.example — committed to repo as documentation
database_password = "REPLACE_WITH_ACTUAL_PASSWORD"
api_key           = "REPLACE_WITH_API_KEY"

Option 2 — Terraform Cloud / HCP Terraform workspace variables:

# Set sensitive variables in Terraform Cloud UI (marked as sensitive — never shown)
# Automatically available when running Terraform from the workspace

Option 3 — HashiCorp Vault:

# Read secrets from Vault at plan/apply time
data "vault_generic_secret" "db" {
  path = "secret/myapp/database"
}

resource "aws_db_instance" "main" {
  password = data.vault_generic_secret.db.data["password"]
}

Option 4 — AWS Secrets Manager / SSM Parameter Store:

data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = "myapp/production/database-password"
}

resource "aws_db_instance" "main" {
  password = data.aws_secretsmanager_secret_version.db_password.secret_string
}

Fix 7: Fix Variable Passing to Modules

Variables defined in the root module are not automatically available inside child modules — they must be explicitly passed:

# Root module — variables.tf
variable "database_password" {
  type = string
}

variable "aws_region" {
  type    = string
  default = "us-east-1"
}

# Root module — main.tf — must pass variables to child modules
module "database" {
  source = "./modules/database"

  # Explicit variable passing — required
  password   = var.database_password  # ← Must be passed in
  region     = var.aws_region
  project    = var.project_name
}

# modules/database/variables.tf — module's own variable declarations
variable "password" {
  type      = string
  sensitive = true
}

variable "region" {
  type = string
}

variable "project" {
  type = string
}

Module variables don’t accept TF_VAR_ directlyTF_VAR_database_password sets the root module variable. The root module must then pass it to the module:

module "database" {
  source   = "./modules/database"
  password = var.database_password  # ← Chain: TF_VAR → root var → module input
}

Still Not Working?

Check current working directory — Terraform looks for terraform.tfvars in the directory where you run the command, not the directory of the .tf files:

# WRONG — running from parent directory
cd /project
terraform plan  # Looks for /project/terraform.tfvars, not /project/terraform/terraform.tfvars

# CORRECT — run from the directory containing .tf files
cd /project/terraform
terraform plan  # Finds /project/terraform/terraform.tfvars

Check for typos in variable names — a TF_VAR_database_Password (capital P) won’t match variable "database_password" (lowercase):

# List all TF_VAR_ environment variables
env | grep ^TF_VAR_
# Compare against variable names in variables.tf

terraform.tfvars vs terraform.tfvars.json — Terraform auto-loads both. The JSON format must use valid JSON (no comments):

// terraform.tfvars.json
{
  "database_password": "my-password",
  "aws_region": "us-east-1",
  "instance_count": 3
}

For related Terraform issues, see Fix: Terraform State Lock and Fix: GitHub Actions Permission Denied.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles