Fix: Terraform Variable Not Set — No Value for Required Variable
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.tfvarsWhy 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.tfvarsis loaded automatically only if it exists in the current working directory with that exact name.*.tfvarsfiles with other names require-var-file=filename.tfvarsto be passed explicitly.TF_VAR_environment variables are read, but the casing must match exactly (case-sensitive).-varflags 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 subdirectoryRunning 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.tfvarsFix 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 automaticallyIn 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 varFix 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.). Usesensitive = truewithout 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 valuesUse *.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.tfFix 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 workspaceOption 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_ directly — TF_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.tfvarsCheck 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.tfterraform.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.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Terraform Import Error — Resource Not Importable or State Conflict
How to fix Terraform import errors — terraform import syntax, import blocks (Terraform 1.5+), state conflicts, provider-specific import IDs, and importing existing infrastructure.
Fix: Terraform Error Acquiring State Lock — State Lock Conflict
How to fix Terraform state lock errors — understanding lock mechanisms, safely force-unlocking stuck locks, preventing lock conflicts in CI/CD, and using remote backends correctly.
Fix: Helm Not Working — Release Already Exists, Stuck Upgrade, and Values Not Applied
How to fix Helm 3 errors — release already exists, another operation is in progress, --set values not applied, nil pointer template errors, kubeVersion mismatch, hook failures, and ConfigMap changes not restarting pods.
Fix: nginx Upstream Load Balancing Not Working — All Traffic Hitting One Server
How to fix nginx load balancing issues — upstream block configuration, health checks, least_conn vs round-robin, sticky sessions, upstream timeouts, and SSL termination.